Oracle新老SQL写法对比

📅 2026/7/8 8:26:11 👁️ 阅读次数 📝 编程学习
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;
对比项NVLCOALESCE
标准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

十二、总结一张对照表(速查)

场景老写法新写法
内连接, + WHEREJOIN … ON
外连接(+)LEFT/RIGHT JOIN
条件分支DECODECASE
空值处理NVLCOALESCE
分页ROWNUMOFFSET/FETCH
存在判断COUNT(*)+ROWNUM=1EXISTS + FETCH

十三、给你的实战建议(很实用)

  1. 读老代码:必须会老写法
  2. 写新代码:优先用 ANSI SQL
  3. 重构老 SQL
    • 先不改逻辑
    • 只把, + WHEREJOIN ON
  4. 性能别乱动:老 SQL 很多“反直觉写法”是为性能服务的