ODPS JOIN(MaxComputer) 与 Oracle JOIN 用法对比

目录

    • [一、基本 JOIN 类型](#一、基本 JOIN 类型)
      • [1. 单独一个 `JOIN` 等价于 `INNER JOIN`](#1. 单独一个 JOIN 等价于 INNER JOIN)
      • [2. `LEFT JOIN` / `RIGHT JOIN` 用法一致](#2. LEFT JOIN / RIGHT JOIN 用法一致)
      • [3. 关联键重复导致数据翻倍](#3. 关联键重复导致数据翻倍)
    • [二、ODPS 与 Oracle 的主要差异](#二、ODPS 与 Oracle 的主要差异)
      • [1. `(+)` 语法差异(重要)](#1. (+) 语法差异(重要))
      • [2. 半连接示例:`LEFT SEMI JOIN`](#2. 半连接示例:LEFT SEMI JOIN)
      • [3. `LEFT ANTI JOIN`(ODPS 特有)](#3. LEFT ANTI JOIN(ODPS 特有))
    • [三、多表 JOIN 顺序与优化](#三、多表 JOIN 顺序与优化)
    • 四、完整示例对比
    • 五、注意事项汇总

ODPS(MaxCompute)的 JOIN 语法与 Oracle 高度相似,但在一些细节上存在差异。以下将逐一说明。

一、基本 JOIN 类型

JOIN 类型 ODPS 语法 Oracle 语法 说明
内连接(INNER JOIN) JOININNER JOIN JOININNER JOIN 两者完全一致,只返回匹配的行。
左外连接(LEFT JOIN) LEFT JOINLEFT OUTER JOIN LEFT JOINLEFT OUTER JOIN 返回左表全部行,右表无匹配则为 NULL。
右外连接(RIGHT JOIN) RIGHT JOINRIGHT OUTER JOIN RIGHT JOINRIGHT OUTER JOIN 返回右表全部行,左表无匹配则为 NULL。
全外连接(FULL JOIN) FULL JOINFULL OUTER JOIN FULL JOINFULL OUTER JOIN 返回两表全部行,无匹配的一侧为 NULL。
交叉连接(CROSS JOIN) CROSS JOIN CROSS JOIN 返回笛卡尔积。
半连接 / 反连接 LEFT SEMI JOINLEFT ANTI JOIN(ODPS特有) EXISTS / NOT EXISTSIN / NOT IN ODPS 提供了专门的半连接语法,性能更好。

1. 单独一个 JOIN 等价于 INNER JOIN

sql 复制代码
-- ODPS 与 Oracle 一致
SELECT *
FROM table_a a
JOIN table_b b ON a.id = b.id;
-- 等价于
SELECT *
FROM table_a a
INNER JOIN table_b b ON a.id = b.id;

2. LEFT JOIN / RIGHT JOIN 用法一致

sql 复制代码
-- 左连接:保留左表所有记录
SELECT a.id, a.name, b.order_date
FROM customers a
LEFT JOIN orders b ON a.id = b.cust_id;

3. 关联键重复导致数据翻倍

无论 ODPS 还是 Oracle,只要 JOIN 的关联键在任一侧存在重复值,结果行数都可能翻倍(相当于一对多或多对多)。

sql 复制代码
-- 左表:id=1 出现两次
-- 右表:id=1 出现三次
-- 结果会产生 2×3 = 6 行 id=1 的记录
SELECT *
FROM left_table a
JOIN right_table b ON a.id = b.id;

注意 :若需避免数据翻倍,可提前去重或使用 DISTINCT、聚合函数等。

二、ODPS 与 Oracle 的主要差异

差异点 ODPS Oracle
旧式外连接语法((+) 不支持 (+) 语法 支持 WHERE a.id = b.id(+) 表示左外连接
半连接语法 LEFT SEMI JOIN / LEFT ANTI JOIN 无直接等价语法,需用 EXISTS / NOT EXISTS
JOIN 条件写法 必须使用 ON 子句,不支持 USING 支持 USING(column) 简化相同列名关联
NULL 比较行为 标准 SQL:NULL = NULL 结果为 NULL(不匹配) 相同
MAPJOIN 提示 支持 /*+ MAPJOIN(small_table) */ 优化小表 支持 /*+ USE_HASH(table) */ 等不同提示

1. (+) 语法差异(重要)

Oracle 允许在 WHERE 中使用 (+) 表示外连接,ODPS 不支持 ,必须使用标准的 LEFT/RIGHT/FULL JOIN

sql 复制代码
-- Oracle 旧式语法(不推荐,但可用)
SELECT *
FROM emp e, dept d
WHERE e.dept_id = d.dept_id(+);   -- 左外连接

-- ODPS 必须改写为:
SELECT *
FROM emp e
LEFT JOIN dept d ON e.dept_id = d.dept_id;

2. 半连接示例:LEFT SEMI JOIN

ODPS 的 LEFT SEMI JOIN 只返回左表中与右表匹配的记录,且不返回右表任何列(类似 EXISTS)。

sql 复制代码
-- ODPS:查询有订单的客户(不关心订单详情)
SELECT a.id, a.name
FROM customers a
LEFT SEMI JOIN orders b ON a.id = b.cust_id;

-- Oracle 等价写法:
SELECT a.id, a.name
FROM customers a
WHERE EXISTS (SELECT 1 FROM orders b WHERE a.id = b.cust_id);

3. LEFT ANTI JOIN(ODPS 特有)

返回左表中没有 匹配右表的记录(类似 NOT EXISTS)。

sql 复制代码
-- ODPS:查询从未下过订单的客户
SELECT a.id, a.name
FROM customers a
LEFT ANTI JOIN orders b ON a.id = b.cust_id;

三、多表 JOIN 顺序与优化

  • ODPS :优化器会自动重排 JOIN 顺序,但可通过 /*+ MAPJOIN(table) */ 强制将小表加载到内存。
  • Oracle :优化器基于统计信息选择最优顺序,也可使用 ORDERED 提示强制顺序。

MAPJOIN 示例(ODPS)

sql 复制代码
SELECT /*+ MAPJOIN(dim_date) */ *
FROM fact_sales a
JOIN dim_date b ON a.date_key = b.date_key;

四、完整示例对比

场景:员工表(emp)与部门表(dept)左连接,获取所有员工及其部门名称。

ODPS

sql 复制代码
SELECT e.empno, e.ename, d.dname
FROM emp e
LEFT JOIN dept d ON e.deptno = d.deptno;

Oracle(标准语法相同,也支持旧式):

sql 复制代码
-- 标准语法(推荐)
SELECT e.empno, e.ename, d.dname
FROM emp e
LEFT JOIN dept d ON e.deptno = d.deptno;

-- 旧式语法(仅 Oracle)
SELECT e.empno, e.ename, d.dname
FROM emp e, dept d
WHERE e.deptno = d.deptno(+);

五、注意事项汇总

  1. 关联键重复导致数据膨胀:这是 SQL JOIN 的通用行为,并非 ODPS 或 Oracle 特有。务必检查关联键的唯一性。
  2. NULL 值处理NULL 与任何值(包括 NULL)比较均为 NULL,导致不匹配。若需将 NULL 视为相等,需使用 NVLCOALESCE 转换。
  3. 性能优化 :大表 JOIN 时,ODPS 中常用 MAPJOIN 提示;Oracle 中则常用 USE_HASHUSE_NL
  4. 字符串类型隐式转换:ODPS 对隐式转换限制较严,建议显式转换类型;Oracle 较宽松但可能引发索引失效。
  5. 分区表 JOIN :ODPS 中 JOIN 前尽量裁剪分区(WHERE partition_col = ...),可大幅减少数据扫描量。

ODPS 的 JOIN 核心功能与 Oracle 保持一致 ,只需注意 (+) 旧语法不支持、以及半连接语法的差异即可轻松迁移。建议统一使用标准 SQL 的 JOIN ... ON 语法。

相关推荐
小碗羊肉8 分钟前
【MySQL | 第七篇】索引
数据库·mysql
m0_4954964114 分钟前
SQL中如何获取前N个最大值并排除自己_利用窗口函数限制
jvm·数据库·python
m0_7406532214 分钟前
mysql如何提取日期中的年份_使用year函数从日期中截取
jvm·数据库·python
hanyi_qwe20 分钟前
Mysql 与 Nginx 双机高可用
数据库·mysql·nginx
S1998_1997111609•X22 分钟前
login:/-system.web,dex.dmp,b-scode:app·%
网络·数据库·百度·facebook·twitter
运气好好的24 分钟前
mysql数据库日志文件过大如何清理_定期备份与重置日志文件
jvm·数据库·python
2401_831419441 小时前
如何防止MongoDB副本集被误初始化_副本集名称(replSetName)锁定
jvm·数据库·python
阿丰资源1 小时前
基于Spring Boot的美容院管理系统(附源码+数据库+文档)
数据库·spring boot·后端
徐子童1 小时前
复合索引会失效的场景
数据库·mysql·面试题·索引失效
abc123456sdggfd1 小时前
解决Socket图像传输中断问题:基于分块接收与可靠发送的完整教程
jvm·数据库·python