SQL 多表访问

SQL 多表访问 (★★★)

#open-sql #sql-joins #database

数据库视图

方面 详情
定义位置 ABAP 字典(SE11)
可包含 表的 JOIN、选择、投影
在 Open SQL 中 当作透明表使用
维护 如果视图启用维护则可能
1
SELECT * FROM dd_view_name INTO TABLE lt_data WHERE ...
💡数据库视图封装 JOIN 逻辑。使用它们简化 ABAP 代码中重复的 JOIN。

INNER JOIN(内连接)

  • 仅返回两表中匹配的行
  • 最常见的 JOIN 类型
1
2
3
4
5
6
7
SELECT s~carrid, s~connid, p~cityfrom, p~cityto
INTO TABLE lt_result
FROM sflight AS s
INNER JOIN spfli AS p
ON s~carrid = p~carrid AND
s~connid = p~connid
WHERE s~carrid = 'LH'.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
表 A(左)       表 B(右)
+----+------+ +----+-------+
| K1 | A1 | | K1 | B1 |
+----+------+ +----+-------+
| 01 | X | | 01 | Y |
| 02 | Z | | 03 | W |
+----+------+ +----+-------+

INNER JOIN 结果:
+----+------+----+-------+
| K1 | A1 | K1 | B1 |
+----+------+----+-------+
| 01 | X | 01 | Y | ← 仅匹配的键
+----+------+----+-------+

LEFT OUTER JOIN(左外连接)

  • 返回左表的所有行加上右表中匹配的行
  • 没有匹配时右侧列为 NULL
  • 右侧只允许一个表
1
2
3
4
5
6
SELECT s~carrid, s~connid, p~cityfrom
INTO TABLE lt_result
FROM sflight AS s
LEFT OUTER JOIN spfli AS p
ON s~carrid = p~carrid AND
s~connid = p~connid.
1
2
3
4
5
6
7
LEFT OUTER JOIN 结果:
+----+------+----+-------+
| K1 | A1 | K1 | B1 |
+----+------+----+-------+
| 01 | X | 01 | Y | ← 找到匹配
| 02 | Z | -- | NULL | ← 无匹配,右侧为 NULL
+----+------+----+-------+
⚠️LEFT OUTER JOIN 右侧只能有一个表。不能在右侧外连接到视图或其他 JOIN 结果。

JOIN 列命名

当两个表共享列名时,使用 alias~column 语法避免歧义:

1
2
3
FROM sflight AS s
INNER JOIN spfli AS p
ON s~carrid = p~carrid " alias~column 表示法
表示法 含义
alias~column 限定来自特定表的列
~column 快捷方式(如果不歧义)
column 如果在多个表中则歧义

子查询

标量子查询

在 WHERE 子句中返回单个值:

1
2
3
SELECT * FROM sflight
INTO TABLE lt_flights
WHERE price > ( SELECT AVG(price) FROM sflight ).

IN 子查询

返回一组值:

1
2
3
SELECT * FROM sflight
INTO TABLE lt_result
WHERE carrid IN ( SELECT carrid FROM scarr WHERE currcode = 'EUR' ).
子查询类型 返回值 配合使用
标量 单个值 =<>
集合 多个值 INNOT IN
📌子查询绕过 SAP 表缓冲(被缓冲视为 Native SQL 路径)。

FOR ALL ENTRIES

将数据库表与内表连接:

1
2
3
4
5
6
7
8
9
" 关键:先检查驱动表!
IF lt_keys IS NOT INITIAL.
SELECT carrid, connid, price
INTO TABLE lt_result
FROM sflight
FOR ALL ENTRIES IN lt_keys
WHERE carrid = lt_keys-carrid
AND connid = lt_keys-connid.
ENDIF.

FOR ALL ENTRIES 规则

规则 详情
检查 IS NOT INITIAL 空驱动表读取整个数据库表
自动去重 结果自动删除重复行
不适用于大数据量 驱动表很大时性能下降
不能使用 LIKE、NOT IN WHERE 中受限的运算符
如果驱动表(内表)为FOR ALL ENTRIES 的行为如同没有 WHERE 子句,读取整个数据库表。始终先检查 itab IS NOT INITIAL

性能提示

1
2
3
4
5
6
7
8
9
10
11
12
" 不好:驱动表未排序、有重复
SELECT * FROM sflight
FOR ALL ENTRIES IN lt_dirty
WHERE carrid = lt_dirty-carrid.

" 好:先精简驱动表
SORT lt_dirty BY carrid.
DELETE ADJACENT DUPLICATES FROM lt_dirty COMPARING carrid.

SELECT * FROM sflight
FOR ALL ENTRIES IN lt_dirty
WHERE carrid = lt_dirty-carrid.

性能反模式:循环中的 SELECT

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
" 反模式:循环中的 SELECT
LOOP AT lt_flights INTO ls_flight.
SELECT SINGLE cityfrom INTO ls_flight-cityfrom
FROM spfli
WHERE carrid = ls_flight-carrid
AND connid = ls_flight-connid.
MODIFY lt_flights FROM ls_flight.
ENDLOOP.

" 正确:使用 JOIN 或预缓冲
SELECT s~carrid, s~connid, p~cityfrom
INTO TABLE lt_result
FROM sflight AS s
INNER JOIN spfli AS p
ON s~carrid = p~carrid AND s~connid = p~connid.
方式 数据库往返次数 性能
循环中的 SELECT n + 1(每行一次) 很差
JOIN 1 优秀
FOR ALL ENTRIES 1(或少量) 小集合时良好
预缓冲 + READ 1 + 内存查找 良好

JOIN 比较

特性 INNER JOIN LEFT OUTER JOIN
未匹配的左表行 丢弃 保留(右侧 = NULL)
右侧限制 仅一个表
绕过缓冲
ON 条件 必需 必需
默认 JOIN 类型 INNER(关键字可选) 必须指定 OUTER

考试/测试模式

关键词 / 短语 答案
“FOR ALL ENTRIES 空表” 读取整个数据库表 – 始终检查 IS NOT INITIAL
“LEFT OUTER JOIN 右侧限制” 右侧只允许一个表
“JOIN 和表缓冲” JOIN 绕过 SAP 表缓冲
“别名列语法” alias~column 消除歧义
“FOR ALL ENTRIES 去重处理” 结果集自动删除重复项
“循环中的 SELECT” 反模式;使用 JOIN 或预缓冲
“精简驱动表” FOR ALL ENTRIES 前 SORT + DELETE ADJACENT DUPLICATES
“标量子查询返回” 单个值
“IN 子查询返回” 一组值

相关笔记