SQL SELECT 子句高级用法解析

1次阅读

select别名不能在where中使用,因为sql执行顺序为from→where→group by→select→order by,where阶段别名尚未生成;应改用having、重写原表达式或子查询/cte。

SQL SELECT 子句高级用法解析

SELECT 中的表达式别名为什么不能在 WHERE 里用

因为 SQL 执行顺序是 FROM → WHERE → GROUP BY → SELECT → ORDER BYWHERE 发生在 SELECT 之前,所以你在 SELECT 里写的 price * 1.1 AS final_price,在 WHERE 阶段根本还不存在。

常见错误现象:Unknown column 'final_price' in 'where clause'

  • 想过滤计算结果?改用 HAVING(配合 GROUP BY)或直接在 WHERE 写原表达式,比如 WHERE price * 1.1 > 100
  • 如果表达式复杂又重复用,考虑子查询或 CTE,避免写两遍
  • mysql 8.0+ 和 postgresql 支持在 WHERE 后加 LATERAL,但日常没必要绕这么远

ORDER BY 里用数字序号是偷懒还是隐患

ORDER BY 2 表示按 SELECT 列表中第 2 个字段排序,语法合法,但非常脆弱。

使用场景:临时查数据、SQL 自动生成脚本里偶尔出现

  • 列顺序一变,排序就错——比如你把 SELECT name, age 改成 SELECT age, nameORDER BY 2 就从按 age 变成按 name
  • 加了表达式或函数后,序号容易数错,比如 SELECT id, UPPER(name), created_at + INTERVAL 1 DAY,第三个字段不是原始列
  • 团队协作或长期维护时,没人愿意猜“2”到底对应啥,可读性归零

SELECT * 在 JOIN 查询里到底多危险

不只是性能问题,更常引发列名冲突和隐式覆盖。

常见错误现象:两个表都有 id 字段,SELECT * FROM users JOIN orders ON ... 返回两个 id,客户端取值时只拿到第一个,或者报 Column 'id' in field list is ambiguous

  • 显式列出需要的字段,必要时加表别名前缀,比如 users.id, orders.order_id, users.name
  • 如果真要“全选”,用 users.*, orders.order_id, orders.status 这种混合写法,避开重名字段
  • ORM 或中间件自动拼 * 时,检查它是否做了字段去重或别名处理,别默认它靠谱

NULL 在 SELECT 表达式里的传播逻辑怎么绕过去

NULL 参与任何运算(+||CASE 外部条件)结果基本都是 NULL,不是空字符串也不是 0,这点很多人下意识忽略。

使用场景:拼接用户姓名(可能缺 middle_name)、计算折扣后价格(discount 可能为 NULL)

  • COALESCE(col, '') 替代直接拼接,比如 first_name || ' ' || COALESCE(middle_name, '') || ' ' || last_name
  • 数值计算前先兜底:price * COALESCE(discount_rate, 0),而不是 price * discount_rate
  • 注意 COALESCE 是标准 SQL,但某些老系统用 ISNULL()(SQL Server)或 NVL()oracle),跨库迁移时得换

最麻烦的其实是嵌套层级深的表达式——一个中间值为 NULL,整条链就断,调试时得一层层 SELECT 拆开验,不能只看最终结果是不是空。

text=ZqhQzanResources