Oracle新老SQL写法对比
Oracle 的“老写法”本质上是ANSI SQL:1989 / SQL-92 之前的风格,在金融、电信、银行系统里非常常见。下面按类型 + 示例 + 现代等价写法 + 踩坑点给你系统梳理一遍,和你刚才那条 SQL 属于同一个“时代产物”。
一、隐式连接(Implicit JOIN)✅ 你刚遇到的
老写法
SELECT*FROMEMP E,DEPT DWHEREE.DEPTNO=D.DEPTNO;新写法
SELECT*FROMEMP EJOINDEPT DONE.DEPTNO=D.DEPTNO;📌本质:逗号 = CROSS JOIN,WHERE = 过滤条件
📌风险:少写一个条件就变笛卡尔积
二、(+)外连接(Oracle 独有)
这是 Oracle 最著名的“老古董”。
左外连接(老)
SELECTE.ENAME,D.DNAMEFROMEMP E,DEPT DWHEREE.DEPTNO=D.DEPTNO(+);左外连接(新)
SELECTE.ENAME,D.DNAMEFROMEMP ELEFTJOINDEPT DONE.DEPTNO=D.DEPTNO;右外连接(老)
SELECTE.ENAME,D.DNAMEFROMEMP E,DEPT DWHEREE.DEPTNO(+)=D.DEPTNO;规则口诀(非常重要)
(+)写在“补空的一边”
❌ 不支持:
- 全外连接
FULL OUTER JOIN - 多个
OR条件 - 自连接 +
(+)
✅ Oracle 官方建议:12c 以后尽量不用(+)
三、DECODE替代 CASE(老牌条件表达式)
老写法
SELECTDECODE(SEX,'1','男','2','女','未知')ASSEX_DESCFROMEMP;新写法
SELECTCASESEXWHEN'1'THEN'男'WHEN'2'THEN'女'ELSE'未知'ENDASSEX_DESCFROMEMP;📌DECODE是 Oracle 私有函数
📌CASE是 ANSI 标准,可读性强
四、NVLvsCOALESCE
老写法
SELECTNVL(COMM,0)FROMEMP;新写法
SELECTCOALESCE(COMM,0)FROMEMP;| 对比项 | NVL | COALESCE |
|---|---|---|
| 标准 | Oracle 私有 | ANSI SQL |
| 参数个数 | 2 个 | ≥2 个 |
| 短路求值 | ❌ | ✅ |
📌COALESCE更安全,尤其跨数据库
五、SYSDATE+ 数字 = 日期运算(老习惯)
老写法
SELECTSYSDATE+1FROMDUAL;-- 明天SELECTSYSDATE-1/24FROMDUAL;-- 一小时前新写法(更语义化)
SELECTSYSDATE+INTERVAL'1'DAYFROMDUAL;SELECTSYSDATE-INTERVAL'1'HOURFROMDUAL;📌 老写法在金融计息、账期计算中极常见
📌 新写法可读性更好,但性能没差别
六、ROWNUM分页(经典老写法)
老写法
SELECT*FROM(SELECTA.*,ROWNUM RNFROM(SELECT*FROMEMPORDERBYHIREDATEDESC)AWHEREROWNUM<=20)WHERERN>10;新写法(12c+)
SELECT*FROMEMPORDERBYHIREDATEDESCOFFSET10ROWSFETCHNEXT10ROWSONLY;📌ROWNUM是 Oracle 特有
📌OFFSET / FETCH是 ANSI SQL
七、SELECT COUNT(*) INTO V_CNT FROM ... WHERE ROWNUM=1
老写法(判断是否存在)
SELECTCOUNT(*)INTOV_CNTFROMEMPWHEREDEPTNO=10ANDROWNUM=1;新写法
SELECT1INTOV_FLAGFROMEMPWHEREDEPTNO=10FETCHFIRST1ROWSONLY;📌 老写法是为了性能优化(找到一条就停)
八、EXISTS里的SELECT 1(老习惯)
老写法
SELECT*FROMEMP EWHEREEXISTS(SELECT1FROMDEPT DWHERED.DEPTNO=E.DEPTNO);说明
SELECT 1是历史习惯- Oracle 实际不关心 SELECT 列表
SELECT NULL也一样
📌 这是“老派写法”,不是错误
九、||字符串拼接(Oracle 传统)
老写法
SELECT'A'||'B'FROMDUAL;新写法(ANSI)
SELECTCONCAT('A','B')FROMDUAL;📌||是 Oracle / PostgreSQL 风格
📌CONCAT在 MySQL / SQL Server 中更通用
十、HINT写在注释里(Oracle 特色)
老写法
SELECT/*+ INDEX(E EMP_IDX) */*FROMEMP E;📌 注释不是注释,是优化器指令
📌 这种“伪装成注释的语法”是 Oracle 独有
十一、你这条 SQL 里还藏着的“老味儿”
结合你刚才的 SQL,其实还有这些老特征:
| 特征 | 老/新 |
|---|---|
| 逗号 + WHERE 关联 | 老 |
| LAG 窗口函数 | 新 |
| 多层子查询 | 老 |
| GROUP BY 长字段拼接 | 老 |
| 无 WITH(CTE) | 老 |
| 无 JOIN ON | 老 |
十二、总结一张对照表(速查)
| 场景 | 老写法 | 新写法 |
|---|---|---|
| 内连接 | , + WHERE | JOIN … ON |
| 外连接 | (+) | LEFT/RIGHT JOIN |
| 条件分支 | DECODE | CASE |
| 空值处理 | NVL | COALESCE |
| 分页 | ROWNUM | OFFSET/FETCH |
| 存在判断 | COUNT(*)+ROWNUM=1 | EXISTS + FETCH |
十三、给你的实战建议(很实用)
- 读老代码:必须会老写法
- 写新代码:优先用 ANSI SQL
- 重构老 SQL:
- 先不改逻辑
- 只把
, + WHERE→JOIN ON
- 性能别乱动:老 SQL 很多“反直觉写法”是为性能服务的
