当前位置: 首页 > news >正文

SQL语法基础教程

本文档详细讲解SQL的基础语法和概念。


一、SQL语句分类

1. DDL - 数据定义语言(Data Definition Language)

作用:定义和管理数据库对象(表、视图、索引等)

命令说明示例
CREATE创建CREATE TABLE 表名 (...)
ALTER修改ALTER TABLE 表名 ADD (列名 类型)
DROP删除DROP TABLE 表名
TRUNCATE清空TRUNCATE TABLE 表名

特点

  • DDL操作会自动提交(COMMIT)

  • 不能回滚(ROLLBACK)

  • 修改表结构时要特别小心


2. DML - 数据操纵语言(Data Manipulation Language)

作用:操作表中的数据

命令说明示例
SELECT查询SELECT * FROM 表名
INSERT插入INSERT INTO 表名 VALUES (...)
UPDATE更新UPDATE 表名 SET 列=值 WHERE 条件
DELETE删除DELETE FROM 表名 WHERE 条件

特点

  • DML操作需要手动COMMIT才能生效

  • 可以ROLLBACK撤销

  • 本实验主要是DML中的SELECT查询


3. DCL - 数据控制语言(Data Control Language)

作用:控制用户权限

命令说明示例
GRANT授权GRANT SELECT ON 表名 TO 用户
REVOKE撤销REVOKE SELECT ON 表名 FROM 用户

二、SELECT语句完整语法

基本结构

SELECT [DISTINCT] 列名
FROM 表名
[WHERE 条件]
[GROUP BY 列名]
[HAVING 条件]
[ORDER BY 列名 [ASC|DESC]]

执行顺序(重要!)

1. FROM      --> 确定查询哪个表
2. WHERE     --> 过滤行(分组前)
3. GROUP BY  --> 分组
4. HAVING    --> 过滤组(分组后)
5. SELECT    --> 选择显示的列
6. ORDER BY  --> 排序
7. DISTINCT  --> 去重

为什么顺序重要?

  • WHERE在GROUP BY之前,所以不能使用聚合函数

  • HAVING在GROUP BY之后,可以使用聚合函数

  • SELECT的别名在ORDER BY中可用,但在WHERE中不可用

示例理解

SELECT 出版单位, AVG(单价) AS 平均单价
FROM 书目
WHERE 单价 > 20              -- ✅ 可以:WHERE在SELECT前执行
-- WHERE 平均单价 > 30      -- ❌ 错误:平均单价别名还不存在
GROUP BY 出版单位
HAVING AVG(单价) > 30        -- ✅ 可以:HAVING在GROUP BY后
ORDER BY 平均单价 DESC;      -- ✅ 可以:ORDER BY在SELECT后,别名已存在

三、基础语法详解

1. SELECT - 选择列

-- 选择所有列
SELECT * FROM 书目;
​
-- 选择指定列
SELECT 书名, 作者 FROM 书目;
​
-- 使用别名
SELECT 书名 AS 图书名称, 作者 AS 作者姓名 FROM 书目;
-- AS可以省略
SELECT 书名 图书名称, 作者 作者姓名 FROM 书目;
​
-- 计算列
SELECT 书名, 单价, 单价 * 0.8 AS 折扣价 FROM 书目;

DISTINCT去重

-- 查询所有不同的出版单位
SELECT DISTINCT 出版单位 FROM 书目;
​
-- 查询所有不同的(出版单位, 图书分类号)组合
SELECT DISTINCT 出版单位, 图书分类号 FROM 书目;

2. FROM - 指定表

-- 单表
FROM 书目
​
-- 表别名
FROM 书目 s            -- s是别名
FROM 书目 AS s         -- AS可加可不加

为什么要用表别名?

  1. 简化书写:s.书名书目.书名 简洁

  2. 多表查询时必需:区分同名列

  3. 自连接时必需:同一个表要用不同别名


3. WHERE - 过滤行

基本比较运算符

运算符说明示例
=等于WHERE 单价 = 30
!= 或 <>不等于WHERE 单价 <> 30
>大于WHERE 单价 > 30
>=大于等于WHERE 单价 >= 30
<小于WHERE 单价 < 30
<=小于等于WHERE 单价 <= 30

逻辑运算符

运算符说明示例
AND且(都要满足)WHERE 单价 > 20 AND 单价 < 40
OR或(满足一个即可)WHERE 出版单位='人民出版社' OR 出版单位='作家出版社'
NOT非(取反)WHERE NOT 出版单位='人民出版社'

范围查询

-- BETWEEN...AND... (包含边界值)
WHERE 单价 BETWEEN 20 AND 40
-- 等价于
WHERE 单价 >= 20 AND 单价 <= 40
​
-- IN (...) 在列表中
WHERE 出版单位 IN ('人民出版社', '作家出版社')
-- 等价于
WHERE 出版单位='人民出版社' OR 出版单位='作家出版社'

模糊查询

-- LIKE 模糊匹配
-- % : 匹配任意长度的任意字符(包括0个)
-- _ : 匹配单个任意字符
​
WHERE 书名 LIKE '红%'      -- 以"红"开头
WHERE 书名 LIKE '%梦'      -- 以"梦"结尾
WHERE 书名 LIKE '%数据库%'  -- 包含"数据库"
WHERE 书名 LIKE '红_梦'    -- "红"和"梦"之间有一个字符
WHERE 书名 LIKE '__'       -- 恰好两个字符的书名

NULL值判断

-- 判断是否为NULL
WHERE 归还日期 IS NULL         -- ✅ 正确
WHERE 归还日期 = NULL          -- ❌ 错误(永远为FALSE)-- 判断是否不为NULL
WHERE 归还日期 IS NOT NULL     -- ✅ 正确
WHERE 归还日期 != NULL         -- ❌ 错误(永远为FALSE)

为什么不能用 = NULL?

  • NULL表示"未知"

  • "未知"不等于任何值,包括"未知"本身

  • NULL = NULL 的结果是NULL(不是TRUE也不是FALSE)

  • 只有IS NULL能正确判断NULL


4. ORDER BY - 排序

-- 单列排序
ORDER BY 单价 ASC         -- 升序(从小到大),ASC可省略
ORDER BY 单价 DESC        -- 降序(从大到小)
ORDER BY 单价             -- 默认升序-- 多列排序
ORDER BY 单价 DESC, 书名 ASC
-- 先按单价降序,单价相同再按书名升序-- 使用列的位置(不推荐,可读性差)
SELECT 书名, 单价 FROM 书目
ORDER BY 2 DESC;          -- 按第2列(单价)降序-- 使用别名
SELECT 书名, 单价 AS 价格 FROM 书目
ORDER BY 价格 DESC;       -- 使用别名排序

NULL值的排序

ORDER BY 归还日期         -- NULL值排在最前面
ORDER BY 归还日期 NULLS LAST  -- NULL值排在最后面

5. 聚合函数

五大聚合函数

-- COUNT(*) : 统计行数(包括NULL)
SELECT COUNT(*) FROM 借阅;                -- 总借阅次数-- COUNT(列) : 统计非NULL值的数量
SELECT COUNT(归还日期) FROM 借阅;         -- 已归还的次数-- SUM(列) : 求和
SELECT SUM(单价) FROM 书目;               -- 所有书的单价总和-- AVG(列) : 平均值
SELECT AVG(单价) FROM 书目;               -- 平均单价-- MAX(列) : 最大值
SELECT MAX(单价) FROM 书目;               -- 最贵的书价格-- MIN(列) : 最小值
SELECT MIN(单价) FROM 书目;               -- 最便宜的书价格

COUNT(*)和COUNT(列)的区别

-- 假设表中有5行,其中2行的归还日期为NULLSELECT COUNT(*) FROM 借阅;              -- 结果:5(包括NULL)
SELECT COUNT(归还日期) FROM 借阅;       -- 结果:3(只统计非NULL)
SELECT COUNT(DISTINCT 借书证号) FROM 借阅;  -- 统计不同的借书证号数量

注意事项

  1. 聚合函数忽略NULL值(COUNT(*)除外)

  2. 聚合函数不能用在WHERE中(要用HAVING)

  3. SELECT中有聚合函数时,其他列要么也是聚合函数,要么在GROUP BY中


6. GROUP BY - 分组

基本语法

SELECT 分组列, 聚合函数(列)
FROM 表名
GROUP BY 分组列;

示例

-- 统计每个出版社的书目数量
SELECT 出版单位, COUNT(*) AS 书目数量
FROM 书目
GROUP BY 出版单位;-- 统计每个出版社的书目数量和平均单价
SELECT 出版单位, COUNT(*) AS 书目数量,AVG(单价) AS 平均单价
FROM 书目
GROUP BY 出版单位;

GROUP BY的规则

规则1:SELECT中非聚合列必须在GROUP BY中

-- ❌ 错误:书名不在GROUP BY中
SELECT 出版单位, 书名, COUNT(*) 
FROM 书目
GROUP BY 出版单位;-- ✅ 正确:书名加入GROUP BY
SELECT 出版单位, 书名, COUNT(*) 
FROM 书目
GROUP BY 出版单位, 书名;

为什么?

  • GROUP BY将数据分组,每组返回一行

  • 如果书名不在GROUP BY中,数据库不知道该显示该组的哪个书名

规则2:GROUP BY中的列可以不在SELECT中

-- ✅ 正确:按出版单位分组,但不显示出版单位
SELECT COUNT(*) AS 总数量
FROM 书目
GROUP BY 出版单位;

7. HAVING - 过滤分组

HAVING vs WHERE

特性WHEREHAVING
作用对象行(原始数据)组(分组后的结果)
执行时机GROUP BY之前GROUP BY之后
能否使用聚合函数

示例对比

-- 查询单价>20的书,按出版社分组,显示平均单价>30的出版社SELECT 出版单位, AVG(单价) AS 平均单价
FROM 书目
WHERE 单价 > 20              -- WHERE: 过滤行(分组前)
GROUP BY 出版单位
HAVING AVG(单价) > 30        -- HAVING: 过滤组(分组后)
ORDER BY 平均单价 DESC;-- 执行流程:
-- 1. FROM 书目
-- 2. WHERE 单价 > 20  (先过滤掉单价<=20的书)
-- 3. GROUP BY 出版单位  (对剩余的书按出版社分组)
-- 4. HAVING AVG(单价) > 30  (过滤掉平均单价<=30的组)
-- 5. SELECT
-- 6. ORDER BY

常见错误

-- ❌ 错误:WHERE中不能用聚合函数
SELECT 出版单位, AVG(单价)
FROM 书目
WHERE AVG(单价) > 30        -- 错误!WHERE不能用AVG
GROUP BY 出版单位;-- ✅ 正确:应该用HAVING
SELECT 出版单位, AVG(单价)
FROM 书目
GROUP BY 出版单位
HAVING AVG(单价) > 30;

四、JOIN连接查询

1. 内连接(INNER JOIN)

语法

SELECT 列名
FROM 表1
INNER JOIN 表2 ON 连接条件;
-- INNER可以省略,直接写JOIN

特点

  • 只返回两表都有匹配的记录

  • 相当于两表的交集

示例

-- 查询借阅信息(只显示有借阅记录的读者)
SELECT d.姓名, s.书名, j.借书日期
FROM 借阅 j
INNER JOIN 读者 d ON j.借书证号 = d.借书证号
INNER JOIN 图书 t ON j.图书编号 = t.图书编号
INNER JOIN 书目 s ON t.ISBN = s.ISBN;

2. 左外连接(LEFT JOIN)

语法

SELECT 列名
FROM 表1
LEFT JOIN 表2 ON 连接条件;

特点

  • 返回左表所有记录

  • 右表没有匹配时显示NULL

示例

-- 查询所有读者的借阅次数(包括没借过书的)
SELECT d.姓名,COUNT(j.借阅流水号) AS 借阅次数
FROM 读者 d
LEFT JOIN 借阅 j ON d.借书证号 = j.借书证号
GROUP BY d.姓名;-- 结果会包括借阅次数为0的读者

LEFT JOIN vs INNER JOIN

-- INNER JOIN:只显示有借阅记录的读者
FROM 读者 d
INNER JOIN 借阅 j ON d.借书证号 = j.借书证号
-- 结果:只有借过书的读者-- LEFT JOIN:显示所有读者
FROM 读者 d
LEFT JOIN 借阅 j ON d.借书证号 = j.借书证号
-- 结果:所有读者,没借过书的借阅次数显示为0或NULL

3. 右外连接(RIGHT JOIN)

语法

SELECT 列名
FROM 表1
RIGHT JOIN 表2 ON 连接条件;

特点

  • 返回右表所有记录

  • 左表没有匹配时显示NULL

  • 不常用(可以调换表顺序用LEFT JOIN替代)


4. 全外连接(FULL JOIN)

语法

SELECT 列名
FROM 表1
FULL JOIN 表2 ON 连接条件;

特点

  • 返回两表所有记录

  • 相当于LEFT JOIN + RIGHT JOIN

  • Oracle支持,MySQL不支持


五、子查询

1. 标量子查询(返回单个值)

-- 查询单价最高的图书
SELECT * FROM 书目
WHERE 单价 = (SELECT MAX(单价) FROM 书目);-- 子查询返回一个值:最高单价

2. 列子查询(返回一列值)

-- 查询借过书的读者
SELECT * FROM 读者
WHERE 借书证号 IN (SELECT DISTINCT 借书证号 FROM 借阅);-- 子查询返回一列值:所有借过书的借书证号

IN vs EXISTS

-- 使用IN
WHERE 借书证号 IN (SELECT 借书证号 FROM 借阅)-- 使用EXISTS(性能通常更好)
WHERE EXISTS (SELECT 1 FROM 借阅 j WHERE j.借书证号 = d.借书证号)

3. 表子查询(返回一个表)

-- 查询借阅次数>2的读者
SELECT * FROM (SELECT 借书证号, COUNT(*) AS 借阅次数FROM 借阅GROUP BY 借书证号
) WHERE 借阅次数 > 2;-- 子查询返回一个临时表

六、常用函数

1. 字符串函数

-- 连接字符串
SELECT 书名 || '(' || 作者 || ')' AS 完整信息 FROM 书目;-- 转换大小写
SELECT UPPER(书名), LOWER(书名) FROM 书目;-- 截取字符串
SELECT SUBSTR(书名, 1, 2) FROM 书目;  -- 截取前2个字符-- 字符串长度
SELECT LENGTH(书名) FROM 书目;

2. 数值函数

-- 四舍五入
SELECT ROUND(单价, 1) FROM 书目;  -- 保留1位小数-- 向上取整
SELECT CEIL(单价) FROM 书目;-- 向下取整
SELECT FLOOR(单价) FROM 书目;-- 截断小数
SELECT TRUNC(单价, 1) FROM 书目;  -- 保留1位小数,不四舍五入

3. 日期函数

-- 当前日期时间
SELECT SYSDATE FROM DUAL;-- 日期相减(结果是天数)
SELECT SYSDATE - 借书日期 AS 已借天数 FROM 借阅;-- 日期加减天数
SELECT 借书日期 + 30 AS 应还日期 FROM 借阅;-- 加减月份
SELECT ADD_MONTHS(借书日期, 1) AS 一个月后 FROM 借阅;-- 提取年月日
SELECT EXTRACT(YEAR FROM 借书日期) AS 年份,EXTRACT(MONTH FROM 借书日期) AS 月份,EXTRACT(DAY FROM 借书日期) AS 日期
FROM 借阅;-- 日期格式化
SELECT TO_CHAR(借书日期, 'YYYY-MM-DD') AS 格式化日期 FROM 借阅;

4. NULL处理函数

-- NVL(值1, 值2) : 如果值1为NULL,返回值2
SELECT NVL(罚金, 0) AS 罚金 FROM 罚款分类;-- NVL2(值1, 值2, 值3) : 如果值1非NULL返回值2,否则返回值3
SELECT NVL2(归还日期, '已还', '未还') AS 状态 FROM 借阅;-- COALESCE(值1, 值2, 值3, ...) : 返回第一个非NULL值
SELECT COALESCE(归还日期, 借书日期, SYSDATE) FROM 借阅;

5. CASE表达式

-- 简单CASE
SELECT 书名,CASE 是否借出WHEN '是' THEN '已借出'WHEN '否' THEN '可借'ELSE '未知'END AS 状态
FROM 图书;-- 搜索CASE(更常用)
SELECT 书名,单价,CASE WHEN 单价 < 20 THEN '低价'WHEN 单价 < 40 THEN '中价'ELSE '高价'END AS 价格等级
FROM 书目;

七、常见错误及解决

错误1:SELECT的列不在GROUP BY中

-- ❌ 错误
SELECT 出版单位, 书名, COUNT(*)
FROM 书目
GROUP BY 出版单位;-- 错误信息:ORA-00979: not a GROUP BY expression-- ✅ 解决:把书名加入GROUP BY
SELECT 出版单位, 书名, COUNT(*)
FROM 书目
GROUP BY 出版单位, 书名;

错误2:WHERE中使用聚合函数

-- ❌ 错误
SELECT 出版单位, AVG(单价)
FROM 书目
WHERE AVG(单价) > 30
GROUP BY 出版单位;-- 错误信息:ORA-00934: group function is not allowed here-- ✅ 解决:用HAVING代替WHERE
SELECT 出版单位, AVG(单价)
FROM 书目
GROUP BY 出版单位
HAVING AVG(单价) > 30;

错误3:NULL值判断错误

-- ❌ 错误
SELECT * FROM 借阅
WHERE 归还日期 = NULL;-- 查不到任何结果(因为NULL=NULL的结果是NULL,不是TRUE)-- ✅ 解决:用IS NULL
SELECT * FROM 借阅
WHERE 归还日期 IS NULL;

错误4:字符串忘记加引号

-- ❌ 错误
SELECT * FROM 书目
WHERE 书名 = 红楼梦;-- 错误信息:ORA-00904: "红楼梦": invalid identifier-- ✅ 解决:字符串要用单引号
SELECT * FROM 书目
WHERE 书名 = '红楼梦';

错误5:日期格式错误

-- ❌ 错误
INSERT INTO 借阅 VALUES (1, '20051001', '2001231', '2010-09-19', NULL, NULL, NULL);-- 可能报错或插入错误的日期-- ✅ 解决:使用TO_DATE函数
INSERT INTO 借阅 VALUES (1, '20051001', '2001231', TO_DATE('2010-09-19', 'YYYY-MM-DD'), NULL, NULL, NULL
);

八、学习建议

1. 从简单到复杂

  1. 第一步:单表查询(SELECT、WHERE、ORDER BY)

  2. 第二步:聚合统计(COUNT、SUM、AVG、GROUP BY)

  3. 第三步:多表连接(JOIN)

  4. 第四步:子查询

  5. 第五步:复杂综合查询

2. 多练习、多思考

  • 不要只看代码,要动手写

  • 理解为什么这么写

  • 尝试用不同方法解决同一个问题

3. 理解执行流程

  • 记住SELECT语句的执行顺序

  • 理解每个子句的作用

  • 知道为什么有些语法不能用

4. 善用注释

  • 在复杂查询中添加注释

  • 说明查询的目的和逻辑

  • 方便日后维护


九、快速参考

SQL关键字速查

关键字作用位置
SELECT选择列开头
FROM指定表SELECT后
WHERE过滤行FROM后
GROUP BY分组WHERE后
HAVING过滤组GROUP BY后
ORDER BY排序最后
JOIN连接表FROM中
AND/OR逻辑运算WHERE/HAVING中
IN在列表中WHERE中
LIKE模糊查询WHERE中
IS NULL判断NULLWHERE中

运算符优先级

  1. 括号 ()

  2. 比较运算 =, !=, >, <, >=, <=

  3. NOT

  4. AND

  5. OR

建议:使用括号明确优先级,提高可读性


希望这份教程能帮助你更好地理解SQL语法!继续加油!💪

http://www.dtcms.com/a/568766.html

相关文章:

  • 算法25.0
  • 无穿戴动捕技术:解锁动作捕捉新维度,拓展多元应用边界
  • 高速PCB设计指南(5)
  • 栈与队列---算法题
  • 外包加工网站开发一个网页具体流程
  • 泰安肥城做网站的公司平台推广活动策划方案
  • 衡石科技跨平台数据网关技术解析:实现多源异构数据整合的新范式
  • 计算机网络实验04:IP与ICMP数据报分析实验
  • 基于python的天气预报系统设计和可视化数据分析源码+报告
  • lerobot so-arm101复现步骤
  • 司马阅与数之境科技达成生态战略合作,释放1+1>2的产业赋能价值
  • IE跳转Chrome浏览器及静默打包
  • Chrome恢复关闭网页的快捷键
  • python报修网站开发源码建设网站遇到的问题
  • 深入解析 Qt QListWidget 控件:功能、实现与最佳实践
  • Qt在线安装问题
  • Qt Quick ApplicationQt Quick Application (compat)
  • 快速搭建分布式链路追踪系统:SkyWalking全攻略
  • 45 C++智能指针的原理与模拟实现,内存泄漏与RAII
  • 时序数据库系列(二):InfluxDB安装配置从零搭建
  • Rust实战开发之图形界面开发入门(egui crate)
  • 如何在centos 中运行arm64程序
  • 工业时序数据库TDengine 架构、性能与实战全解析
  • 朗迪锋@2025人因工程与智能系统交互国际会议
  • django初识与安装
  • 哪个网站做译员好设计页面跳转
  • 嘉兴网站制作费用手机html5网站开发
  • <P2016 战略游戏>
  • OpenCV环境配置(QT 6.6.1 MSVC2019 64bit + OpenCV – 4.12.0)
  • 用zookpeer搭建Hadoop的HA集群,组件启动的启动顺序是什么?