首页 > 解决方案 > 为什么 T-SQL CROSS APPLY 有时表现得像 LEFT JOIN

问题描述

我读过的大多数文档都表明 CROSS APPLY 的行为方式与 INNER JOIN 类似,只有在两个源表中都有匹配的行时,才会在输出中包含一行。

但是,情况似乎并非总是如此,例如,如果您运行以下 SQL 查询,结果将包含 3 行,其中一个包含许多 NULL,因为右侧表中没有行:

CREATE TABLE #Order
(
    Id          int PRIMARY KEY
)

CREATE TABLE #OrderItem
(
    OrderId     int NOT NULL,
    Price       decimal(18, 2) NOT NULL
)

INSERT INTO #Order
VALUES(1), (2), (3)

INSERT INTO #OrderItem
VALUES(1, 10), (1, 20), (3,100)

SELECT *
FROM #Order o
CROSS APPLY
(
    SELECT SUM(Price) AS TotalPrice, COUNT(*) AS Items, MIN(Price) AS MinPrice
    FROM #OrderItem
    WHERE OrderId = o.Id
) t

DROP TABLE #Order
DROP TABLE #OrderItem

有谁知道这是为什么?

标签: sql-servercross-apply

解决方案


TL;博士;

发生这种情况的原因是聚合是一个标量聚合。


有两种类型的聚合:

  • 矢量聚合

    • 需要一个GROUP BY子句

    • 如果输入没有行,则根本不返回任何行

  • 标量聚合

    • GROUP BY条款

    • 即使没有输入行,也始终返回至少一行。COUNT退货0,别人退货NULL

您使用的是标量聚合,因此总是返回一行。

要获得矢量聚合,您需要添加一个GROUP BY

SELECT *
FROM #Order o
CROSS APPLY
(
    SELECT SUM(oi.Price) AS TotalPrice, COUNT(*) AS Items, MIN(oi.Price) AS MinPrice
    FROM #OrderItem oi
    WHERE oi.OrderId = o.Id   -- always specify inner table in column references
    GROUP BY ()   -- the empty set
-- alternatively
    GROUP BY oi.OrderId
) t

另请参阅@PaulWhite 的这篇优秀文章:标量和向量聚合的乐趣


推荐阅读