📊 SQL 入门 Day 1:SELECT & WHERE — 数据查询的基本功

知识点简介

SELECTWHERE 是 SQL 最核心的两个子句------一个决定「看什么列」,一个决定「看哪些行」。

看似简单,但里边藏着不少细节:去重、多条件组合、NULL 处理、性能陷阱...都是面试必考、实战必用的知识点。


核心语法详解

1️⃣ SELECT --- 选择列

sql 复制代码
-- 查询所有列(生产环境慎用)
SELECT * FROM users;

-- 查询指定列
SELECT id, name, email FROM users;

-- 列别名(AS 可省略)
SELECT name AS 用户名, email AS 邮箱 FROM users;

-- 表达式计算
SELECT name, salary, salary * 1.1 AS 加薪后 FROM employees;

-- 常量列
SELECT '员工' AS 类型, name FROM users;

💡 最佳实践 :生产环境避免 SELECT *,一是明文传输多余字段有安全风险,二是索引覆盖会失效(回表查询)。

2️⃣ DISTINCT --- 去重

sql 复制代码
-- 单列去重
SELECT DISTINCT department FROM employees;

-- 多列去重(两列组合唯一才视为重复)
SELECT DISTINCT department, position FROM employees;

-- 聚合中去重
SELECT COUNT(DISTINCT department) FROM employees;

⚠️ DISTINCT 是对结果集做全排序去重,数据量大时性能差。如果只是「有没有重复记录」,用 EXISTS 替代。

3️⃣ WHERE --- 筛选行

sql 复制代码
-- 精确匹配
SELECT * FROM users WHERE id = 100;

-- 字符串匹配(注意要用单引号)
SELECT * FROM users WHERE name = '张三';

-- 比较运算符
SELECT * FROM products WHERE price > 100;
SELECT * FROM orders WHERE amount >= 500;
SELECT * FROM tasks WHERE created_at < '2026-01-01';

4️⃣ AND / OR / NOT --- 逻辑组合

sql 复制代码
-- AND:同时满足(优先级高于 OR)
SELECT * FROM employees
WHERE department = '技术部' AND salary > 10000;

-- OR:满足任一
SELECT * FROM employees
WHERE department = '技术部' OR department = '产品部';

-- NOT:取反
SELECT * FROM products
WHERE NOT discontinued;

-- 组合使用(AND 优先于 OR,建议加括号)
SELECT * FROM orders
WHERE (status = '已支付' OR status = '已发货')
  AND amount > 500;

⚠️ 易错点 :SQL 里 AND 优先级高于 ORWHERE a=1 OR b=2 AND c=3 等价于 WHERE a=1 OR (b=2 AND c=3),不是你直觉的 (a=1 OR b=2) AND c=3

5️⃣ IN / BETWEEN / IS NULL

sql 复制代码
-- IN:值列表匹配
SELECT * FROM employees
WHERE department IN ('技术部', '产品部', '设计部');

-- NOT IN:排除(注意 NULL 陷阱!)
SELECT * FROM employees
WHERE department NOT IN ('实习生');  -- 安全,无 NULL

-- BETWEEN:范围匹配(闭区间,包含两端)
SELECT * FROM products
WHERE price BETWEEN 100 AND 500;

-- IS NULL:检查空值(不能写 = NULL!)
SELECT * FROM customers
WHERE phone IS NULL;

-- IS NOT NULL
SELECT * FROM customers
WHERE phone IS NOT NULL;

⚠️ 经典面试题WHERE col NOT IN (1, 2, NULL) 的结果永远是空!因为 col <> NULL 的结果是 UNKNOWNWHERE 只保留 TRUE 的记录。

6️⃣ 执行顺序(面试必问)

sql 复制代码
SELECT   department, COUNT(*) AS 人数    -- 3.
FROM     employees                       -- 1.
WHERE    status = '在职'                 -- 2.
ORDER BY 人数 DESC;                      -- 4.

执行顺序FROMWHERESELECTORDER BY

这就是为什么 WHERE 中可以使用表的原始字段,但不能使用 SELECT 中的别名

sql 复制代码
-- ❌ 错误:WHERE 执行时别名 含税价 还未定义
SELECT name, salary * 1.13 AS 含税价
FROM employees
WHERE 含税价 > 10000;

-- ✅ 正确:使用原始列或子查询
SELECT name, salary * 1.13 AS 含税价
FROM employees
WHERE salary * 1.13 > 10000;

只有 HAVINGORDER BY 可以使用别名(因为它们在第 3 步之后执行)。


实战案例

场景:员工查询系统

sql 复制代码
-- 建表
CREATE TABLE employees (
    id SERIAL PRIMARY KEY,
    name VARCHAR(50),
    department VARCHAR(50),
    salary NUMERIC(10,2),
    join_date DATE,
    is_active BOOLEAN DEFAULT true
);

-- 插入测试数据
INSERT INTO employees (name, department, salary, join_date, is_active) VALUES
('张三', '技术部', 15000, '2023-03-15', true),
('李四', '技术部', 18000, '2022-06-01', true),
('王五', '产品部', 12000, '2024-01-10', true),
('赵六', '设计部', 9000,  '2024-07-20', false),
('钱七', '产品部', 11000, '2023-11-05', true);

-- 实战 1:技术部月薪过万的在职员工
SELECT name, salary
FROM employees
WHERE department = '技术部'
  AND salary >= 10000
  AND is_active = true;

-- 结果:
-- | name | salary |
-- | 张三  | 15000  |
-- | 李四  | 18000  |

-- 实战 2:2023年入职的非技术部员工
SELECT name, department, join_date
FROM employees
WHERE join_date BETWEEN '2023-01-01' AND '2023-12-31'
  AND department != '技术部';

-- 结果:
-- | name | department | join_date |
-- | 赵六  | 设计部      | 2024-...   |
-- 不对,赵六是2024年入职的。实际结果应该是:
-- | name | department | join_date |
-- | 钱七  | 产品部      | 2023-11-05|

-- 实战 3:工资 9000-12000 的在职员工
SELECT name, department, salary
FROM employees
WHERE salary BETWEEN 9000 AND 12000
  AND is_active = true;

-- 结果:
-- | name | department | salary |
-- | 王五  | 产品部      | 12000  |
-- | 钱七  | 产品部      | 11000  |
-- ⚠️ BETWEEN 包含两端值,12000 也算在内

常见坑点 / 注意事项

坑点 错误写法 正确写法
NULL 判断 col = NULL col IS NULL
字符串值 WHERE name = "张三" WHERE name = '张三'
BETWEEN 边界 以为不包括端点 实际是闭区间 [a, b]
AND/OR 优先级 a=1 OR b=2 AND c=3 (a=1 OR b=2) AND c=3
WHERE 用别名 WHERE alias > 10 子查询或重写条件
NOT IN 有 NULL NOT IN (1, NULL) 空结果 NOT EXISTS 替代
DISTINCT 性能 大表无脑 DISTINCT 优先用 EXISTS 或聚合
浮点相等 WHERE price = 0.1 ABS(price - 0.1) < 0.001

📌 今日总结

  • SELECT 决定输出列,WHERE 决定筛选行
  • 执行顺序:FROMWHERESELECTORDER BY
  • 三个特殊值列表:INBETWEENIS NULL
  • NULL 的坑:任何 NULL 参与的比较都是 UNKNOWN
  • 括号控制优先级,不到万不得已别依赖默认优先级
相关推荐
苏三说技术1 小时前
为什么越来越多的人使用PostgreSQL?
后端
不一样的少年_1 小时前
不用框架,手搓 AI Agent:(一) 先让它跑起来
前端·后端·agent
用户526835677901 小时前
《拒绝当背锅侠!写了个 WebHook 中间件,让局域网硬件在服务挂掉时“喊”出来》
后端
云技纵横2 小时前
线上报 Deadlock,怎么从日志里找出是哪两条 SQL 打架?
后端
卷无止境2 小时前
Python数据进阶专题:用声明式验证让数据管道告别"惊喜"
后端·python·数据分析
glartchen2 小时前
win11下使用 WSL2 部署kali 虚拟机(不踩坑版)
后端
聂二AI落地内参2 小时前
ComfyUI 平台化:能力契约、节点白名单和积分预扣怎么串起来
后端
用户7827110810632 小时前
Spring MVC RESTful 员工管理实战 ——踩坑全记录
后端
SimonKing2 小时前
Spring I18N 底层源码大揭秘:你的 MessageSource 到底是怎么找到配置的?
java·后端·程序员