MySQL中的交叉/外部应用
Posted
技术标签:
【中文标题】MySQL中的交叉/外部应用【英文标题】:CROSS/OUTER APPLY in MySQL 【发布时间】:2016-08-20 12:50:35 【问题描述】:我需要在 mysql(EC2 RDS MySQL 实例)中使用 CROSS APPLY。 看起来 MySQL 无法识别 CROSS APPLY 语法。有人可以帮帮我吗?
这是查询。
SELECT ORD.ID
,ORD.NAME
,ORD.DATE
,ORD_HIST.VALUE
FROM ORD
CROSS APPLY (
SELECT TOP 1 ORD_HISTORY.VALUE
FROM ORD_HISTORY
WHERE ORD.ID = ORD_HISTORY.ID
AND ORD.DATE <= ORD_HISTORY.DATE
ORDER BY ORD_HISTORY.DATE DESC
) ORD_HIST
【问题讨论】:
WHERE
子句看起来有问题。 ORD.DATE
之前应该有一个AND
吗?
You might want to look at this 或 perhaps at this。祝你好运。
我很抱歉@BobJarvis,现在已经修改了查询。
【参考方案1】:
从 MySQL 8.0.14 开始,您可以使用 LATERAL
:
现在可以在派生表前面加上 LATERAL 关键字,以指定允许在同一个 FROM 子句中引用(依赖于)前面表的列。 使用 LATERAL 指定的派生表只能出现在 FROM 子句中,要么出现在用逗号分隔的表列表中,要么出现在连接规范(JOIN、INNER JOIN、CROSS JOIN、LEFT [OUTER] JOIN 或 RIGHT [OUTER] JOIN)中。横向派生表使某些 SQL 操作成为可能,这些操作不能用非横向派生表完成,或者需要效率较低的解决方法
CROSS APPLY () <=> ,LATERAL ()
OUTER APPLY () <=> LEFT JOIN LATERAL () ON 1=1
Support for LATERAL derived tables added to MySQL 8.0.14
在这种情况下:
SELECT ORD.ID
,ORD.NAME
,ORD.DATE
,ORD_HIST.VALUE
FROM ORD,
LATERAL (
SELECT ORD_HISTORY.VALUE
FROM ORD_HISTORY
WHERE ORD.ID = ORD_HISTORY.ID
AND ORD.DATE <= ORD_HISTORY.DATE
ORDER BY ORD_HISTORY.DATE DESC
LIMIT 1
) ORD_HIST;
如果相关子查询未返回任何行,则将跳过来自主查询的主行。在这种情况下,应该使用LEFT JOIN LATERAL
。
db<>fiddle demo
【讨论】:
你能解释一下LEFT JOIN LATERAL () ON 1=1
是什么意思吗?该语法在 MySql 8.0.18 中不起作用
@YvánEcarri 当然,添加了一个示例来说明这种情况。【参考方案2】:
基于@lujas szozda 的回答:
对于交叉申请:
SELECT ORD.ID
,ORD.NAME
,ORD.DATE
,ORD_HIST.VALUE
FROM ORD JOIN
LATERAL (
SELECT ORD_HISTORY.VALUE
FROM ORD_HISTORY
WHERE ORD.ID = ORD_HISTORY.ID
AND ORD.DATE <= ORD_HISTORY.DATE
ORDER BY ORD_HISTORY.DATE DESC
LIMIT 1
) ORD_HIST ON 1=1
/* ON 1=1 is just a trick to join to whatever the LATERAL returns */
对于外部应用:
SELECT ORD.ID
,ORD.NAME
,ORD.DATE
,ORD_HIST.VALUE
FROM ORD LEFT JOIN
LATERAL (
SELECT ORD_HISTORY.VALUE
FROM ORD_HISTORY
WHERE ORD.ID = ORD_HISTORY.ID
AND ORD.DATE <= ORD_HISTORY.DATE
ORDER BY ORD_HISTORY.DATE DESC
LIMIT 1
) ORD_HIST ON 1=1
/* ON 1=1 is just a trick to join to whatever the LATERAL returns */
【讨论】:
【参考方案3】:您最接近的 直接 近似值是以相关子查询作为谓词的连接。
SELECT
ORD.ID
,ORD.NAME
,ORD.DATE
,ORD_HISTORY.VALUE
FROM
ORD
INNER JOIN
ORD_HISTORY
ON ORD_HISTORY.<PRIMARY_KEY>
=
(SELECT ORD_HISTORY.<PRIMARY_KEY>
FROM ORD_HISTORY
WHERE ORD.ID = ORD_HISTORY.ID
AND ORD.DATE <= ORD_HISTORY.DATE
ORDER BY ORD_HISTORY.DATE DESC
LIMIT 1
)
但是,在您的情况下,您只需要目标表中的一个字段。这意味着您可以直接在 SELECT 语句中使用相关子查询。
SELECT
ORD.ID
,ORD.NAME
,ORD.DATE
,(SELECT ORD_HISTORY.VALUE
FROM ORD_HISTORY
WHERE ORD.ID = ORD_HISTORY.ID
AND ORD.DATE <= ORD_HISTORY.DATE
ORDER BY ORD_HISTORY.DATE DESC
LIMIT 1
) AS VALUE
FROM
ORD
【讨论】:
我尝试了第一个解决方案对于 ORD 表中的 7k 记录真的很慢。真的很怀念SQL SERVER。以上是关于MySQL中的交叉/外部应用的主要内容,如果未能解决你的问题,请参考以下文章