如何在 LEFT JOIN ON 子句中使用子选择?
Posted
技术标签:
【中文标题】如何在 LEFT JOIN ON 子句中使用子选择?【英文标题】:How to use a subselect in a LEFT JOIN ON clause? 【发布时间】:2022-01-23 19:27:28 【问题描述】:我有一张桌子和
ORD_DATE | ORD_ID | ORD_REF | ORD_TYPE1 | ORD_TYPE2 | PRODNUM | PRODQUAL | PRICE |
---|---|---|---|---|---|---|---|
2020-09-01 | 101 | 101 | ORDER | ORDER | 456 | F | 555 |
2020-09-02 | 102 | 101 | CONF | ORDER | 456 | F | 555 |
2020-11-30 | 103 | 102 | ORDER | ORDER | 123 | K | 444 |
2020-12-01 | 104 | 102 | CONF | ORDER | 123 | K | 444 |
2020-12-01 | 105 | 103 | ORDER | ORDER | 123 | K | 444 |
2020-12-01 | 106 | 104 | ORDER | ORDER | 123 | K | 333 |
2020-12-02 | 107 | 104 | CONF | ORDER | 123 | K | 333 |
2020-12-08 | 108 | 104 | CONF | RETURN | 123 | K | -333 |
2020-12-01 | 109 | 105 | ORDER | ORDER | 123 | F | 222 |
2020-12-02 | 110 | 105 | CONF | ORDER | 123 | F | 222 |
和一个表:
ORD_DATE | PROD_NUMBER | PROD_QUAL |
---|---|---|
2020-12-01-00.00.00.000000 | 123 | K |
2020-12-01-00.00.00.000000 | 123 | L |
表中是“二手”的产品。
如果产品在该表中,则表示表 t 中的所有销售额ORDER_TYPE_1 = "ORDER" AND ORDER_TYPE_2 = "ORDER" AND t.ORD_DATE >= s.ORD_DATE AND t.PROD_NUMBER = s.PROD_NUMBER AND t.PROD_QUAL = s.PROD_QUAL
算作“二手”。
我需要从 2021 年和第 12 个月确认的所有“二手”销售额的总和。但只有带有 CONF/ORDER 或 CONF/RETURN 的行应该在计算中。为此,我在表 t 中有 CAL_YEAR 和 CAL_MONTH(为减少混乱而省略)。
从表 t 中,只有 ORDER_REF 105 匹配,总和将为 0,因为只有这 2 行很重要:
| 2020-12-02 | 107 | 104 | CONF | ORDER | 123 | K | 333
| 2020-12-08 | 108 | 104 | CONF | RETURN | 123 | K | -333
到目前为止我的代码:
SELECT SUM(PRICE)
FROM t
--
LEFT JOIN s
ON t.PRODNUM = s.PRODNUM
AND t.PRODQUAL = s.PRODQUAL
AND (SELECT ORD_DATE FROM t WHERE ORDER_TYPE_1 = 'ORDER' AND ORDER_TYPE_2 = 'ORDER') >= s.ORD_DATE
--
WHERE CAL_YEAR = 2021
AND CAL_MONTH = 12
AND ORDER_TYPE_1 = 'CONF'
AND ORDER_TYPE_2 IN ('ORDER', 'RETURN')
--
GROUP BY PRICE
;
SQL 错误:“单行子查询返回多行
我的问题是将 LEFT JOIN 限制为 ORDER/ORDER(以便 ORDER_REF 105 进入),但仅使用 CONF/ORDER 和 CONF/RETURN 作为总和(以便 ORDER_REF 102 退出)。
有人可以帮忙吗?
【问题讨论】:
连接条件中是否需要子查询不清楚...不能直接说t.order_type_1 = 'ORDER'...
吗?但我认为我更大的问题是,如果t
拥有您需要的所有信息,您为什么还要加入s
?
当产品开始作为“二手”出售时,没有任何信息。该信息仅在表 s 中。
啊,我的错。感谢您的澄清。 (当我读到“如果产品在该表中,则表示表 t 中的所有销售额”,我认为它的意思是“s 是……表 t 中的所有销售额”。)我仍然不清楚你为什么想要一个但是,连接条件中的子查询,而不是引用您正在加入的 t
。
请edit 将minimal reproducible example 包含在您的示例数据的预期输出中。
改为加入子查询,
【参考方案1】:
我能想到的最简单的方法是进行自联接,您可以在其中加入一个 表 t 的第二个副本,别名为 t2
,用于 CONF/ORDER 和 CONF/RETURN行,而您对 ORDER/ORDER 行使用 t
。
SELECT SUM(t2.PRICE)
FROM t
--
INNER JOIN t t2
ON t2.ORD_REF = t.ORD_REF
AND t2.ORDER_TYPE_1 = 'CONF'
AND t2.ORDER_TYPE_2 IN ('ORDER', 'RETURN')
--
LEFT JOIN s
ON t.PRODNUM = s.PRODNUM
AND t.PRODQUAL = s.PRODQUAL
AND t.ORD_DATE >= s.ORD_DATE
--
WHERE t.CAL_YEAR = 2021
AND t.CAL_MONTH = 12
AND t.ORDER_TYPE_1 = 'ORDER'
AND t.ORDER_TYPE_2 = 'ORDER'
;
如果您需要提高效率,您可以使用分析/窗口函数将总价格从 CONF 行拉入 ORDER/ORDER 行作为新列。这样它只会查询表t
一次而不是两次。
SELECT SUM(t2.order_price_sum)
FROM (select t.*,
sum(case when ORDER_TYPE_1 = 'CONF'
AND ORDER_TYPE_2 IN ('ORDER', 'RETURN')
then t.price
else 0 end) over (partition by ord_ref) as order_price_sum
from t) t2
--
LEFT JOIN s
ON t2.PRODNUM = s.PRODNUM
AND t2.PRODQUAL = s.PRODQUAL
AND t2.ord_date >= s.ORD_DATE
--
WHERE CAL_YEAR = 2021
AND CAL_MONTH = 12
AND ORDER_TYPE_1 = 'ORDER'
AND ORDER_TYPE_2 = 'ORDER'
;
【讨论】:
以上是关于如何在 LEFT JOIN ON 子句中使用子选择?的主要内容,如果未能解决你的问题,请参考以下文章
为啥以及何时在 WHERE 子句中带有条件的 LEFT JOIN 不等于在 ON 中的相同 LEFT JOIN? [复制]
关于在left join的on子句中限制左边表的取值时出现非期望的结果