SQL中的大小写、trim()、Having()、to_date() 和 to_char()、top

本文介绍了SQL中的基本操作,包括字符串处理函数如TRIM(), UPPER(), LOWER(),以及GROUP BY与HAVING子句的使用方法。此外还讲解了日期转换函数TO_DATE和TO_CHAR的用法,并对比了不同数据库中TOP子句的不同实现。

一、trim()将字符中指定位置的指定字符删除

SQL 中的 TRIM 函数是用来移除掉一个字串中的字头或字尾。最常见的用途是移除字首或字尾的空白。这个函数在不同的资料库中有不同的名称:

  • MySQL: TRIM( ), RTRIM( ), LTRIM( )
  • Oracle: RTRIM( ), LTRIM( )
  • SQL Server: RTRIM( ), LTRIM( )

各种 trim 函数的语法如下:

TRIM ( [ [位置] [要移除的字串] FROM ] 字串): [位置] 的可能值为 LEADING (起头), TRAILING (结尾), or BOTH (起头及结尾)。 这个函数将把 [要移除的字串] 从字串的起头、结尾,或是起头及结尾移除。如果我们没有列出 [要移除的字串] 是什么的话,那空白就会被移除。

LTRIM(字串): 将所有字串起头的空白移除。

RTRIM(字串): 将所有字串结尾的空白移除。

例1

SELECT TRIM('   Sample   ');

结果:

'Sample'

例2

SELECT LTRIM('   Sample   ');

结果:

'Sample   '

例3

SELECT RTRIM('   Sample   ');

结果:

'   Sample'

二、大小写转化,UPPER(),LOWER()

UPPER(****),将****转化为大写;

LOWER(****),将****转化为小写;

例从字符串"Hello World"中提取”ello world“

<pre name="code" class="sql">SELECT LOWER(TRIM('H' FROM 'Hello World')) FROM dual
 

三、having() 与 group by 

这两者组合相当于where与select组合,不过having()中可以使用聚合函数

例选择表ppp2中num重复的记录

select * from ppp2
where num in (select num from ppp2 group by num having (count(num)>1))
 

这里可见转载地址: http://www.cnblogs.com/wang-123/archive/2012/01/05/2312676.html

--group by 和having 解释:前提必须了解sql语言中一种特殊的函数:聚合函数,--例如SUM, COUNT, MAX, AVG等。这些函数和其它函数的根本区别就是它们一般作用在多条记录上。 --WHERE关键字在使用集合函数时不能使用,所以在集合函数中加上了HAVING来起到测试查询结果是否符合条件的作用。

create TABLE Table1
    (
        ID int identity(1,1) primary key NOT NULL,   
        classid int, 
        sex varchar(10),
        age int, 
    ) 

     --添加测试数据
Insert into Table1 values(1,'男',20)
    Insert into Table1 values(2,'女',22)
    Insert into Table1 values(3,'男',23)
    Insert into Table1 values(4,'男',22)
    Insert into Table1 values(1,'男',24)
    Insert into Table1 values(2,'女',19)
    Insert into Table1 values(4,'男',26)
    Insert into Table1 values(1,'男',24)
    Insert into Table1 values(1,'男',20)
    Insert into Table1 values(2,'女',22)
    Insert into Table1 values(3,'男',23)
    Insert into Table1 values(4,'男',22)
    Insert into Table1 values(1,'男',24)
    Insert into Table1 values(2,'女',19)

 

--举例子说明:查询table表查询每一个班级中年龄大于20,性别为男的人数select COUNT(*)as '>20岁人数',classid  from Table1 where sex='男' group by classid,age having age>20 --需要注意说明:当同时含有where子句、group by 子句 、having子句及聚集函数时,执行顺序如下:--执行where子句查找符合条件的数据;--使用group by 子句对数据进行分组;对group by 子句形成的组运行聚集函数计算每一组的值;最后用having 子句去掉不符合条件的组。--having 子句中的每一个元素也必须出现在select列表中。有些数据库例外,如oracle.--having子句和where子句都可以用来设定限制条件以使查询结果满足一定的条件限制。--having子句限制的是组,而不是行。where子句中不能使用聚集函数,而having子句中可以。

四、to_date 和 to_char

to_date 就是非日期型转为日期型,to_date('数据 ', 'yyyy-MM-dd hh24:mi:ss'),将数据按照格式产生日期
to_char 就是非字符串型转为字符串,to_char(datetime变量,'yyyy-MM-dd hh24:mi:ss'),将datetime变量按照格式变换日期

五、top,SQL Server和MYSQL、Oracle中相关top是不同的

TOP 子句

TOP 子句用于规定要返回的记录的数目。

对于拥有数千条记录的大型表来说,TOP 子句是非常有用的。

注释:并非所有的数据库系统都支持 TOP 子句。

SQL Server 的语法:

SELECT TOP number|percent column_name(s)
FROM table_name

MySQL 和 Oracle 中的 SQL SELECT TOP 是等价的

MySQL 语法

SELECT column_name(s)
FROM table_name
LIMIT number
例子
SELECT *
FROM Persons
LIMIT 5

Oracle 语法

SELECT column_name(s)
FROM table_name
WHERE ROWNUM <= number
例子
SELECT *
FROM Persons
WHERE ROWNUM <= 5



以下语句有错误,请帮我检查哪里出错了 WITH aaa AS (SELECT DEVICE_ALIAS, TO_CHAR(collect_DATE, 'HH24') ti, MAX(TO_CHAR(collect_DATE, 'HH24:MI')) cnt FROM T_OIL_WELL t WHERE collect_DATE >= TO_DATE(TO_CHAR(SYSDATE -1 , 'yyyy/mm/dd') || ' 14:00', 'yyyy/mm/dd HH24:MI') AND collect_DATE <= TO_DATE(TO_CHAR(SYSDATE , 'yyyy/mm/dd') || ' 14:00', 'yyyy/mm/dd HH24:MI') AND TO_CHAR(collect_DATE, 'HH24') IN ('01', '03', '05', '07', '09', '11', '13', '15', '17', '19', '21', '23') AND CZT = '1' GROUP BY DEVICE_ALIAS, TO_CHAR(collect_DATE, 'HH24')), bbb as ( --厂水井在线,自控仪 and 油压表 select DEVICE_ALIAS, to_char(collect_DATE, 'HH24') ti, max(to_char(collect_DATE, 'HH24:MI')) cnt from T_WATER_WELL a left join daa01 b on trim(a.DEVICE_ALIAS) = trim(b.jh) where collect_DATE >= to_date(to_char(sysdate - 1, 'yyyy/mm/dd') || ' 14:00', 'yyyy/mm/dd HH24:MI') and collect_DATE <= to_date(to_char(sysdate , 'yyyy/mm/dd') || ' 14:00', 'yyyy/mm/dd HH24:MI') and to_char(collect_DATE, 'HH24') in (1, 3, 5, 7, 9, 11, 13, 15, 17, 19, 21, 23) and ((mfq between 0 and 10) and ((substr(b.XQKDM, 1, 3) = 7 and a.TGP between 0 and 25) or (substr(b.XQKDM, 1, 3) <> 7 and a.TGP between 0 and 16))) group by DEVICE_ALIAS, to_char(collect_DATE, 'HH24')), ca_tab_01 as ( --厂上线井历史) --核减长关井等 select jh 上线井 from (select distinct DEVICE_ALIAS jh from T_WATER_WELL_SSSJ a --水井 left join daa01 b on trim(a.DEVICE_ALIAS)=trim(b.jh) where-- ((substr(b.XQKDM,1,3)=7 and a.TGP between 0 and 25 ) or (substr (b.XQKDM,1,3)<>7 and a.TGP between 0 and 16 )) --or (a.mfq between 0 and 10) -- and a.DEVICE_ALIAS not in (select jh from T_CGJH) union all select distinct DEVICE_ALIAS jh from T_OIL_WELL_SSSJ a --油井 where --CZT=1 and DEVICE_ALIAS not in (select jh from T_CGJH) ) a ), cc as (--厂在线井------核减长关井等 select jh1 在线井 from ( --厂油井在线井数 select distinct DEVICE_ALIAS jh1 from (select DEVICE_ALIAS from aaa where DEVICE_ALIAS not in (select jh from T_CGJH) group by DEVICE_ALIAS having (count(DEVICE_ALIAS))>=2 ) union all --厂水井在线井数 select distinct DEVICE_ALIAS jh1 from (select DEVICE_ALIAS from bbb where DEVICE_ALIAS not in (select jh from T_CGJH) group by DEVICE_ALIAS having (count(DEVICE_ALIAS))>=2 ) ) ), AA AS ( SELECT * FROM (select DEVICE_ALIAS, DEVICE_TYPE,ALARM_SYS,ALARM_MESSAGE,ALARM_DESC,ALARM_DATE_FIRST, ALARM_REAL_TIME_DATA,ROW_NUMBER() OVER ( PARTITION BY DEVICE_ALIAS ORDER BY DEVICE_ALIAS,ALARM_SYS DESC) AS XH from t_alarm_result WHERE ALARM_DATE_FIRST>= to_date(to_char(sysdate-1,'yyyy/mm/dd')||' 14:00','yyyy/mm/dd HH24:MI') and ALARM_DATE_FIRST<= to_date(to_char(sysdate,'yyyy/mm/dd')||' 14:00','yyyy/mm/dd HH24:MI') ) WHERE XH=1 ), SELECT A.上线井 AS 异常井, CASE WHEN SUBSTR(e.mqjb, 1, 1) = '1' THEN '油井' WHEN SUBSTR(e.mqjb, 1, 1) = '3' THEN '水井' WHEN SUBSTR(e.mqjb, 1, 1) = 'Z' THEN '油井' ELSE NULL END AS "井别", d.scsj AS 生产时间, d.bzdm AS 代码, d.BZ AS 备注, C.ALARM_SYS, C.ALARM_MESSAGE, C.ALARM_DESC FROM ca_tab_01 a LEFT JOIN cc b ON a.上线井 = b.在线井 LEFT JOIN AA C ON a.上线井 = C.DEVICE_ALIAS LEFT JOIN (SELECT jh, bz, scsj, bzdm FROM DBA01@DQ14_KFSJ_DB_LINK d WHERE D.RQ = TRUNC(SYSDATE) ) d ON a.上线井 = D.JH LEFT JOIN daa01 e ON a.上线井 = e.jh WHERE b.在线井 IS NULL and (SUBSTR(e.mqjb, 1, 1) = '1' or SUBSTR(e.mqjb, 1, 1) = 'Z')
07-18
package com.tal.mx.analysis.index.sqlcheck; import com.tal.mx.analysis.index.app.IndexApplication; import com.tal.mx.analysis.index.models.dto.dataset.SqlInfoDTO; import com.tal.tx.json.JacksonUtil; import com.tal.tx.tools.exception.BizException; import lombok.extern.slf4j.Slf4j; import org.junit.Test; import org.springframework.boot.test.context.SpringBootTest; import java.util.ArrayList; import java.util.HashSet; import java.util.List; import java.util.Set; import java.util.regex.Matcher; import java.util.regex.Pattern; import java.util.stream.Collectors; @Slf4j @SpringBootTest(classes = IndexApplication.class) public class SqlCheck { @Test public void sqlCheck() { String holo="SELECT \n" + " product_id,\n" + " product_name,\n" + " sale_date,\n" + " amount,\n" + " TO_CHAR(sale_date, 'YYYY-MM') AS sale_month,\n" + " SUM(amount) OVER (PARTITION BY product_id ORDER BY sale_date ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW) AS running_total,\n" + " LAG(amount, 1) OVER (PARTITION BY product_id ORDER BY sale_date) AS prev_amount,\n" + " EXTRACT(DOW FROM sale_date) AS day_of_week\n" + "FROM sales_table \n" + "WHERE sale_date >= '2024-01-01'::DATE\n" + "ORDER BY product_id, sale_date"; String sr="SELECT \n" + " product_id,\n" + " product_name,\n" + " sale_date,\n" + " amount,\n" + " date_format(sale_date, '%Y-%m') AS sale_month,\n" + " sum(amount) OVER (PARTITION BY product_id ORDER BY sale_date ROWS UNBOUNDED PRECEDING) AS running_total,\n" + " lag(amount, 1, NULL) OVER (PARTITION BY product_id ORDER BY sale_date) AS prev_amount,\n" + " dayofweek(sale_date) AS day_of_week\n" + "FROM sales_table \n" + "WHERE sale_date >= date('2024-01-01')\n" + "ORDER BY product_id, sale_date"; // 解析HoloDB SQL System.out.println("=== Parsing Holo SQL ==="); SqlInfoDTO holoSqlInfo = parseHoloSql(holo); System.out.println(JacksonUtil.getJSON(holoSqlInfo)); // 解析StarRocks SQL System.out.println("=== Parsing StarRocks SQL ==="); SqlInfoDTO starRocksSqlInfo = parseStarRocksSqlInfo(sr); System.out.println(JacksonUtil.getJSON(starRocksSqlInfo)); // 校验字段数量名称是否一致 System.out.println(checkSqlConsistency(holoSqlInfo, starRocksSqlInfo)); } /** * 解析HoloDB SQL */ private SqlInfoDTO parseHoloSql(String sql) { return parseSqlInfo(sql, true); } /** * 解析StarRocks SQL */ private SqlInfoDTO parseStarRocksSqlInfo(String sql) { return parseSqlInfo(sql, false); } /** * 通用SQL解析方法 */ private SqlInfoDTO parseSqlInfo(String sql, boolean isHolo) { SqlInfoDTO sqlInfo = new SqlInfoDTO(); // 清理SQL String cleanSql = cleanSql(sql); // 提取字段 List<String> fields = extractFields(cleanSql, isHolo); sqlInfo.setFields(fields); // 提取表名 List<String> tables = extractTables(cleanSql, isHolo); sqlInfo.setTables(tables); return sqlInfo; } /** * 清理SQL语句 */ private String cleanSql(String sql) { return sql.replaceAll("--.*", "") // 去除单行注释 .replaceAll("/\\*.*?\\*/", "") // 去除多行注释 .replaceAll("\\s+", " ") // 多个空格替换为单个空格 .trim(); } /** * 提取字段列表 */ private List<String> extractFields(String sql, boolean isHolo) { List<String> fields = new ArrayList<>(); // 匹配SELECTFROM之间的内容 Pattern selectPattern = Pattern.compile("(?i)SELECT\\s+(.*?)\\s+FROM", Pattern.DOTALL); Matcher selectMatcher = selectPattern.matcher(sql); if (selectMatcher.find()) { String selectFields = selectMatcher.group(1).trim(); // 处理SELECT * if ("*".equals(selectFields)) { throw new BizException("不支持SELECT *语法,请明确指定字段"); } // 分割字段 List<String> rawFields = splitFields(selectFields); // 处理每个字段,提取实际字段名(去除别名) for (String field : rawFields) { String actualField = extractActualFieldName(field.trim(), isHolo); if (!actualField.isEmpty()) { fields.add(actualField); } } } return fields; } /** * 提取实际字段名(优先提取别名,其次处理函数) */ private String extractActualFieldName(String field, boolean isHolo) { String trimmedField = field.trim(); // 1. 优先处理AS别名(显式别名) // 直接匹配AS后面的别名,不管前面是什么内容 Pattern asPattern = Pattern.compile("(?i).*AS\\s+([\\w]+)\\s*$"); Matcher asMatcher = asPattern.matcher(trimmedField); if (asMatcher.find()) { return asMatcher.group(1).replaceAll("[\"'`]", ""); } // 2. 处理没有AS别名的字段,直接提取字段名 return extractBaseFieldName(trimmedField); } /** * 检查是否包含复杂表达式 */ private boolean containsComplexExpression(String field) { String upperField = field.toUpperCase(); boolean result = upperField.contains("CASE ") || upperField.contains(" WHEN ") || upperField.contains(" OVER ") || upperField.contains("EXTRACT(") || upperField.contains("TO_CHAR(") || upperField.contains("DATE_FORMAT(") || (field.contains("(") && field.contains(")")); System.out.println("Field '" + field + "' is complex: " + result); return result; } /** * 检查是否为保留关键字 */ private boolean isReservedKeyword(String word) { Set<String> keywords = Set.of("FROM", "WHERE", "GROUP", "ORDER", "HAVING", "LIMIT", "OFFSET", "UNION", "JOIN", "ON", "AND", "OR"); return keywords.contains(word.toUpperCase()); } /** * 提取基础字段名(没有别名的情况) */ private String extractBaseFieldName(String field) { String trimmedField = field.trim(); // 1. 简单字段名(可能带表前缀) if (!trimmedField.contains("(") && !trimmedField.contains(" ")) { // 处理表.字段的情况 if (trimmedField.contains(".")) { String[] parts = trimmedField.split("\\."); return parts[parts.length - 1].replaceAll("[\"'`]", ""); } return trimmedField.replaceAll("[\"'`]", ""); } // 2. 处理简单函数调用(如COUNT(id)、SUM(amount)等) Pattern simpleFuncPattern = Pattern.compile("^\\w+\\s*\\(\\s*([\\w.]+)\\s*\\)\\s*$"); Matcher simpleFuncMatcher = simpleFuncPattern.matcher(trimmedField); if (simpleFuncMatcher.find()) { String innerField = simpleFuncMatcher.group(1); if (innerField.contains(".")) { String[] parts = innerField.split("\\."); return parts[parts.length - 1].replaceAll("[\"'`]", ""); } return innerField.replaceAll("[\"'`]", ""); } // 3. 复杂表达式,返回处理后的字段名 return generateFieldNameFromExpression(trimmedField); } /** * 从复杂表达式生成字段名 */ private String generateFieldNameFromExpression(String expression) { // 移除特殊字符,生成一个合理的字段名 String cleaned = expression.replaceAll("[^\\w\\s]", "_") .replaceAll("\\s+", "_") .replaceAll("_+", "_") .toLowerCase(); // 截取前20个字符作为字段名 if (cleaned.length() > 20) { cleaned = cleaned.substring(0, 20); } // 确保以字母开头 if (!cleaned.matches("^[a-zA-Z].*")) { cleaned = "field_" + cleaned; } return cleaned.replaceAll("_$", ""); // 移除结尾的下划线 } /** * 清理表名 */ private String cleanTableName(String tableName) { return tableName.replaceAll("[\"'`]", "").trim(); } /** * 提取表名列表 */ private List<String> extractTables(String sql, boolean isHolo) { List<String> tables = new ArrayList<>(); Set<String> tableSet = new HashSet<>(); // 用Set去重 // 主表提取 - FROM后面的表 Pattern fromPattern = Pattern.compile("(?i)FROM\\s+([\\w.]+)(?:\\s+(?:AS\\s+)?([\\w]+))?(?=\\s+|\\$)"); Matcher fromMatcher = fromPattern.matcher(sql); if (fromMatcher.find()) { String tableName = fromMatcher.group(1); tableSet.add(cleanTableName(tableName)); } // JOIN表提取 Pattern joinPattern = Pattern.compile("(?i)(?:INNER\\s+|LEFT\\s+|RIGHT\\s+|FULL\\s+)?JOIN\\s+([\\w.]+)(?:\\s+(?:AS\\s+)?([\\w]+))?", Pattern.CASE_INSENSITIVE); Matcher joinMatcher = joinPattern.matcher(sql); while (joinMatcher.find()) { String tableName = joinMatcher.group(1); tableSet.add(cleanTableName(tableName)); } tables.addAll(tableSet); return tables; } /** * 优化分割字段的方法,更好地处理复杂情况 */ private List<String> splitFields(String selectFields) { List<String> fields = new ArrayList<>(); int parenthesesLevel = 0; boolean inQuotes = false; char quoteChar = 0; StringBuilder currentField = new StringBuilder(); for (int i = 0; i < selectFields.length(); i++) { char c = selectFields.charAt(i); // 处理引号 if ((c == '\'' || c == '"') && (i == 0 || selectFields.charAt(i-1) != '\\')) { if (!inQuotes) { inQuotes = true; quoteChar = c; } else if (c == quoteChar) { inQuotes = false; quoteChar = 0; } } if (inQuotes) { currentField.append(c); continue; } // 处理括号 if (c == '(') { parenthesesLevel++; } else if (c == ')') { parenthesesLevel--; } // 顶层逗号作为字段分隔符 if (c == ',' && parenthesesLevel == 0) { String field = currentField.toString().trim(); if (!field.isEmpty()) { fields.add(field); } currentField = new StringBuilder(); } else { currentField.append(c); } } // 最后一个字段 String lastField = currentField.toString().trim(); if (!lastField.isEmpty()) { fields.add(lastField); } return fields; } /** * 校验SQL一致性 */ private boolean checkSqlConsistency(SqlInfoDTO holoSqlInfo, SqlInfoDTO starRocksSqlInfo) { // 检查字段数量 if (holoSqlInfo.getFields().size() != starRocksSqlInfo.getFields().size()) { return false; } // 检查字段名称(忽略大小写) List<String> holoFields = holoSqlInfo.getFields().stream() .map(String::toLowerCase) .sorted() .collect(Collectors.toList()); List<String> starRocksFields = starRocksSqlInfo.getFields().stream() .map(String::toLowerCase) .sorted() .collect(Collectors.toList()); if (!holoFields.equals(starRocksFields)) { return false; } // 检查表名(忽略大小写) Set<String> holoTables = holoSqlInfo.getTables().stream() .map(String::toLowerCase) .collect(Collectors.toSet()); Set<String> starRocksTables = starRocksSqlInfo.getTables().stream() .map(String::toLowerCase) .collect(Collectors.toSet()); return holoTables.equals(starRocksTables); } } 执行结果:=== Parsing Holo SQL === {"fields":["product_id","product_name","sale_date","amount","sale_month","running_total","prev_amount","extract_dow"],"tables":["sales_table"]} === Parsing StarRocks SQL === {"fields":["product_id","product_name","sale_date","amount","sale_month","running_total","prev_amount","day_of_week"],"tables":["sales_table"]} false 优化一下算法,让其匹配正确
最新发布
11-05
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值