【MYSQL】SQL学习指南:从常见错误到高级函数与正则表达式
SQL学习指南:从常见错误到高级函数与正则表达式
本文将通过一个具体的SQL报错案例,带你逐步深入理解SQL查询、聚合函数和正则表达式的使用。内容涵盖错误分析、函数详解和实战示例,适合SQL初学者和需要查漏补缺的开发者。
文章结构概览
一、Unknown column ‘sell_date’ in ‘field list’ 错误解析
错误含义
这个报错直译为:“字段列表中找不到名为’sell_date’的列”。意思是SQL语句中引用了一个不存在的列名。
常见原因分析
原因 | 说明 | 示例 |
---|---|---|
拼写错误 | 列名拼写不正确 | 写成了sel1_date (数字1代替字母l) |
大小写问题 | 数据库区分大小写 | 表中是sellDate 却写了sell_date |
字段位置错误 | 把列名放在了错误的位置 | 在count() 中放入了分组列 |
实际问题案例
看这个有问题的SQL:
select distinct(self_date), count(self_date), product Activities
这个SQL存在多个问题:
count(self_date), product Activities
是非法语法self_date
可能是sell_date
的拼写错误product Activities
部分语法完全错误
正确写法
假设你想统计每天卖了多少种不同的产品:
SELECT sell_date, COUNT(DISTINCT product) AS product_count
FROM Activities
GROUP BY sell_date
ORDER BY sell_date;
实用建议
在写SQL前,先用以下命令查看表结构:
DESCRIBE Activities;
-- 或
SHOW COLUMNS FROM Activities;
二、GROUP_CONCAT函数详解
什么是GROUP_CONCAT?
GROUP_CONCAT是MySQL的专属聚合函数,作用是将分组后的多行数据中的某个字段值拼接成一个字符串,类似于Excel中的TEXTJOIN或Python中的",".join(list)
。
完整语法
GROUP_CONCAT([DISTINCT] 列名[ORDER BY 排序列 ASC|DESC][SEPARATOR '分隔符']
)
使用示例
示例数据表t
id | val |
---|---|
1 | A |
1 | B |
1 | A |
2 | C |
1. 简单拼接
SELECT id, GROUP_CONCAT(val) AS vals
FROM t
GROUP BY id;
结果:
id | vals |
---|---|
1 | A,B,A |
2 | C |
2. 去重 + 排序 + 自定义分隔符
SELECT id,GROUP_CONCAT(DISTINCT valORDER BY val DESCSEPARATOR ' | ') AS vals
FROM t
GROUP BY id;
结果:
id | vals |
---|---|
1 | B |
2 | C |
注意事项
要点 | 说明 |
---|---|
默认长度限制 | 默认拼接结果最长1024字符,超长会被截断 |
修改长度限制 | SET SESSION group_concat_max_len = 1000000; |
跨数据库兼容 | SQL Server用STRING_AGG,PostgreSQL用STRING_AGG,Oracle用LISTAGG |
实战应用:销售数据分组统计
题目要求
- 表:Activities
- 字段:sell_date(日期),product(产品名)
- 需求:按日期分组,统计每天销售的不同产品数量和产品名称列表
解决方案
SELECTsell_date,COUNT(DISTINCT product) AS num_sold,GROUP_CONCAT(DISTINCT product ORDER BY product SEPARATOR ',') AS products
FROM Activities
GROUP BY sell_date
ORDER BY sell_date;
输出示例
sell_date | num_sold | products |
---|---|---|
2020-05-30 | 2 | Basketball,Headphone |
2020-06-01 | 2 | Bible,Pencil |
2020-06-02 | 1 | Mask |
三、COUNT(DISTINCT) 函数深度解析
COUNT()的三种常见用法
写法 | 作用 | 是否忽略NULL |
---|---|---|
COUNT(*) | 统计所有行数 | 不忽略NULL |
COUNT(列名) | 统计该列非NULL的行数 | 忽略NULL |
COUNT(DISTINCT 列名) | 统计该列去重后非NULL值的个数 | 忽略NULL |
为什么用COUNT(DISTINCT product)而不是COUNT(sell_date)?
需求分析
要统计什么 | 用什么列 | 原因 |
---|---|---|
每天 | 按sell_date分组 | 分组依据 |
卖了多少种不同的产品 | COUNT(DISTINCT product) | 需要统计产品种类数 |
示例数据
sell_date | product |
---|---|
2020-06-01 | Apple |
2020-06-01 | Apple |
2020-06-01 | NULL |
2020-06-01 | Banana |
查询与结果
SELECT COUNT(DISTINCT product) AS num_sold
FROM Activities
WHERE sell_date = '2020-06-01';
结果: 2
- Apple重复,只算1次
- NULL被忽略
- 所以结果是2(Apple和Banana)
COUNT(*) vs COUNT(DISTINCT product)
数据示例
sell_date | product |
---|---|
2020-06-01 | Apple |
2020-06-01 | Apple |
2020-06-01 | Banana |
对比结果
SQL | 结果 | 含义 |
---|---|---|
SELECT COUNT(*) FROM Activities WHERE sell_date = '2020-06-01' | 3 | 这一天有3条销售记录 |
SELECT COUNT(DISTINCT product) FROM Activities WHERE sell_date = '2020-06-01' | 2 | 这一天卖过2种产品 |
四、正则表达式REGEXP_LIKE详解
函数语法
REGEXP_LIKE(被匹配字符串, 正则模式 [, 匹配模式])
参数说明
参数 | 含义 | 示例 |
---|---|---|
第1个 | 要匹配的列或字符串 | |
第2个 | 正则表达式 | ‘1[a-zA-Z0-9._-]*@leetcode\.com$’ |
第3个 | 可选标志位 | ‘c’(区分大小写)、‘i’(忽略大小写) |
实际案例解析
REGEXP_LIKE(mail, '^[a-zA-Z][a-zA-Z0-9._-]*@leetcode\\.com$', 'c')
正则模式分解
片段 | 含义 |
---|---|
^ | 字符串开始 |
[a-zA-Z] | 第一个字符必须是字母 |
[a-zA-Z0-9._-]* | 后面跟任意个字母、数字、点、下划线、短横 |
@leetcode\\.com | 字面量@leetcode.com |
$ | 字符串结束 |
'c' | 区分大小写匹配 |
匹配示例
邮箱 | 结果 | 原因 |
---|---|---|
user_123@leetcode.com | ✔ | 合法 |
User@leetcode.com | ✔ | 合法 |
123user@leetcode.com | ✗ | 首字符不是字母 |
user@leetcode.com | ✗ | 大小写敏感,.Com ≠ .com |
user@leetcode.com.cn | ✗ | 后缀多余 |
正则表达式基础知识
常用元字符
符号 | 说明 | 记忆技巧 |
---|---|---|
. | 任意单字符(换行除外) | dot = "点"通配 |
^ | 行首 | 小箭头朝上 |
$ | 行尾 | 小箭头朝下 |
\d | 数字[0-9] | digit |
\D | 非数字[^0-9] | 大写 = 反义 |
\s | 空白字符[\t\n\r] | space |
\S | 非空白 | 大写 = 反义 |
\w | 单词字符[A-Za-z0-9_] | word |
量词说明
符号 | 说明 | 示例 |
---|---|---|
* | 0次或多次 | a* 匹配"", “a”, “aa” |
+ | 1次或多次 | a+ 匹配"a", “aa” |
? | 0次或1次 | a? 匹配"", “a” |
{n} | 恰好n次 | a{3} 匹配"aaa" |
{n,} | 至少n次 | a{2,} 匹配"aa", “aaa” |
为什么用双反斜杠"\."?
转义机制解释
在SQL字符串中使用正则表达式时需要经过两层转义:
你写的 | SQL解析后 | 正则引擎看到 | 含义 |
---|---|---|---|
'@leetcode\\.com' | @leetcode\.com | @leetcode.com | 字面量点 |
'@leetcode.com' | @leetcode.com | @leetcode.com | 任意字符 |
如果只用单反斜杠\.
,SQL会把它当成未知转义序列,直接扔掉反斜杠,导致正则引擎看到的是普通点号,匹配任意字符。
结论: 在MySQL字符串中,要给正则表达式传递字面量点号,必须写成\\.
。
常用正则模板
场景 | 正则模式 | 说明 |
---|---|---|
手机号校验 | ^1[3-9]\d{9}$ | 中国大陆11位手机号 |
提取数字 | -?\d+ | 提取第一个整数(支持负数) |
压缩空白 | \s+ | 将连续空白压缩成单个空格 |
邮箱校验 | ^[a-zA-Z][\w.-]*@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$ | 通用邮箱格式 |
五、总结
通过本文的学习,我们掌握了:
- SQL错误调试:学会分析"Unknown column"类错误,掌握查看表结构的方法
- 高级聚合函数:
- GROUP_CONCAT:字符串拼接利器,支持去重、排序和自定义分隔符
- COUNT(DISTINCT):精确统计唯一值数量
- 正则表达式:
- REGEXP_LIKE函数的使用方法和参数含义
- 常用正则元字符和量词
- SQL中的转义机制
记住,SQL学习是一个循序渐进的过程。遇到错误不要慌张,学会查阅文档、理解错误信息,并多用示例数据进行测试验证。希望这篇文章能帮助你在SQL学习的道路上走得更稳更远!
本文基于实际SQL问题和解决方案整理而成,适用于MySQL数据库。不同数据库系统可能有所差异,请根据实际环境调整。
a-zA-Z ↩︎