SELECT 最简形式怎么写
最基础的
SELECT就是查表里所有行的所有列,语法只有一行:
SELECT * FROM <code>users</code>;
但实际中几乎不这么用——
*会拖慢查询、暴露不该暴露的字段、还容易在表结构变更后让应用出错。真正该从「明确要什么」开始,比如:
SELECT <code>id</code>, <code>name</code>, <code>email</code> FROM <code>users</code>;字段名必须写全,不能省略
AS就直接起别名(如
name username是错的,得写
name AS username) 表名不加反引号也能运行,但一旦表名含短横线、数字开头或关键字(如
order),就必须用
`order`MySQL 默认不区分大小写,但字段别名在结果集中按你写的大小写返回,注意程序里取值时的键名一致性
WHERE 条件里常见的坑
WHERE是过滤核心,但新手常卡在类型隐式转换和空值判断上:
WHERE status = '1'和
WHERE status = 1在
status是字符串类型时行为不同:后者会触发隐式转换,可能使索引失效
WHERE deleted_at != NULL永远不成立,因为
NULL只能用
IS NULL或
IS NOT NULL判断 字符串比较默认走排序规则(collation),
utf8mb4_0900_as_cs区分大小写,而
utf8mb4_general_ci不区分——同一句
WHERE name = 'Admin'在不同库可能结果不同
ORDER BY 和 LIMIT 要一起用才安全
单独写
ORDER BY created_at看似没问题,但如果
created_at有重复值,MySQL 返回顺序其实是不确定的(尤其在 InnoDB 中)。加上
LIMIT后更危险:
SELECT <code>id</code>, <code>title</code> FROM <code>posts</code> ORDER BY <code>created_at</code> LIMIT 10;
这句可能每次执行返回不同
id,因为相同时间戳的行没第二排序字段兜底。正确做法是补一个唯一字段:
SELECT <code>id</code>, <code>title</code> FROM <code>posts</code> ORDER BY <code>created_at</code>, <code>id</code> LIMIT 10;
LIMIT 10, 20这种偏移写法在大数据量下性能差,建议改用游标分页(如
WHERE id > 12345 ORDER BY id LIMIT 20)
ORDER BY字段如果没有索引,会触发 filesort,看
EXPLAIN输出里的
Extra列是否含
Using filesort
JOIN 时 ON 和 WHERE 的区别真关键
左连接(
LEFT JOIN)中,把条件写在
ON还是
WHERE会导致结果完全不同:
SELECT u.<code>name</code>, o.<code>amount</code> FROM <code>users</code> u LEFT JOIN <code>orders</code> o ON u.<code>id</code> = o.<code>user_id</code> AND o.<code>status</code> = 'paid';
上面这句保留所有用户,只关联已支付的订单;但如果把
o.status = 'paid'移到
WHERE:
SELECT u.<code>name</code>, o.<code>amount</code> FROM <code>users</code> u LEFT JOIN <code>orders</code> o ON u.<code>id</code> = o.<code>user_id</code> WHERE o.<code>status</code> = 'paid';
结果就变成「只返回有已支付订单的用户」,等价于内连接。这个细节在报表统计里一不小心就漏掉数据。
多表 JOIN 时,别名必须唯一,
SELECT u.name, u2.name这种写法会报错,得明确写成
u.name AS user_name, u2.name AS manager_name。
