原创 无峰 [ ABAP 技巧与实战 ](javascript:void\(0\);)
一
前言
LEFT JOIN 表示显示左表的全部及关联右表的部分,实际处理时,如果关联的关键字在左表只有一条,但是在右表有N条,
• 结果集显示1条(当右表没有或只有1条时, N=1或0)
• 结果集显示N条(当右表有多条,N>1)
在解决不同字段内容关联的问题时,无意中看到LEFT JOIN 的附加语法MANY TO ONE
.本来以为该语法可以达成仅关联一条的效果.实际测试却发现并发如此.
本文主要介绍LEFT JOIN 中MANY TO ONE 的特点及用法
二
左连接示意图
该示意图未表达连接部分增加记录数的特性.
三
MANY TO ONE 语法介绍
下图是ABAP语法帮助中关于MANY TO ONE 的描述
四
演示数据
测试: 物料 TEST20210203/1 在MARA 中有一行 , 在MARC中有两行.
五
测试场景
以下测试使用 HANA SQL 语句. ABAP SQL语句与之类似.
HANA中使用left out join ABAP中使用 left join .
嵌套SQL的实现方式有很大的差异.
_**01** _
**场景一**
包含两个表的字段.
select a.matnr,b.matnr from mara as a left outer many to one join marc as b on
b.mandt = a.mandt and b.matnr = a.matnr
where a.matnr = 'TEST20210203/1'
结果: 显示两行
_**02** _
**场景二**
仅包含MARA字段
select a.matnr from mara as a left outer many to one join marc as b on b.mandt
= a.mandt and b.matnr = a.matnr
where a.matnr = 'TEST20210203/1'
结果:仅显示一行
_**03** _
**场景三**
计数(*)
select count( * ) from mara as a left outer many to one join marc as b on
b.mandt = a.mandt and b.matnr = a.matnr
where a.matnr = 'TEST20210203/1'
结果:返回值 1.
_**04** _
**场景四**
group 左表字段 count
select a.matnr,count( * ) from mara as a left outer many to one join marc as b
on b.mandt = a.mandt and b.matnr = a.matnr
where a.matnr = 'TEST20210203/1'
group by a.matnr
结果:统计值 1
_**05** _
**场景五**
group 右表字段 count
select b.matnr,count( * ) from mara as a left outer many to one join marc as b
on b.mandt = a.mandt and b.matnr = a.matnr
where a.matnr = 'TEST20210203/1'
group by b.matnr
结果:统计值 2
六
结论
SQL 会根据SELECT LIST 的字段确定是否优化结果的获取. 如果字段没有涉及到 右表, 则视同为没有关联右表,如果涉及到, 再关联右表.
七
用途
似乎没啥用. Left outer join 右表 的目的肯定是要从表中获取数据呀.
唯一的作用, 动态SQL时, 会根据动态设定的字段来确定读取的数据的条目数.
这个语句可以让SQL根据字段的需求自行判断返回的结果集数量.
比如只获取左表内容(抬头表). 则返回抬头一行
如果包含了明细表字段, 则返回明细多行,如果没有明细,返回抬头一行
八
扩展
如果我们关联的右表有多条记录,结果集中包含右表的字段,但是只想显示一条.(第一眼误会MANY TO ONE 子句含义,想达成的目的)
此时针对不同的考虑,应用不同的处理方式
_**01** _
**获取任意一个工厂**
考虑使用 SELECT MATNR,MAX( WERKS) 或 MIN(WERKS).
select a.matnr,max( c.werks ) from mara as a
left outer join marc as c on c.mandt = a.mandt and c.matnr = a.matnr
where a.matnr = 'TEST20210203/1'
group by a.matnr
_**02** _
**多个工厂的采购组一样**
考虑使用 SELECT DISTICT MATNR,EKGRP 但这样做的风险在于, 一旦出现地点的采购组不通的情况, 结果集就会返回多条记录了
select distinct a.matnr,c.ekgrp from mara as a
left outer join marc as c on c.mandt = a.mandt and c.matnr = a.matnr
where a.matnr = 'TEST20210203/1'
_**03** _
**获取最大工厂号的采购组**
则需要使用 rank() 及嵌套SQL 语句了
select * from
( select a.matnr,c.ekgrp ,
rank( ) over( partition by a.matnr order by werks desc ) as zrank
from mara as a
left outer join marc as c on c.mandt = a.mandt and c.matnr = a.matnr
)
where matnr = 'TEST20210203/1' and zrank = 1
如果时最小工厂号,则去掉werks 后面的 desc(表示倒排序)
九
总结
LEFT OUTER JOIN 中的 MANY TO ONE 子句是动态读取抬头表和明细表的SQL语句的一个较为简洁的表达方式.
无需根据查询的字段 动态设置 FROM 子句内容.
用 LEFT OUTER MANY TO ONE 语句关联相关表,
根据字段所在的表,数据库系统自动判断是否需要关联右表(这个说法不一定准确,仅从测试的表现判断的,实际上数据库可能使用其它机制).