内部加入VS CrossApply

时间:2018-08-02 15:31:59

标签: sql sql-server tsql inner-join cross-apply

我正在尝试使用两种不同的方法获得相同的结果,但看来 我在某处做错了,我无法弄清

使用innerjoin的第一个查询:

with cte as(
select *, ROW_NUMBER() OVER(ORDER BY businessentityid desc) AS Row#
from HumanResources.Employee
)
Select A.firstname, B.jobtitle
from Person.Person A
inner join cte B on A.BusinessEntityID = B.BusinessEntityID and B.Row# <= 3

具有交叉应用的第二个查询:

Select A.firstname, cte.jobtitle 
from Person.Person A
cross apply 
(
Select top 3 * 
from HumanResources.Employee B
where B.BusinessEntityID= A.BusinessEntityID
order by businessentityid DESC
) cte

有两种不同的结果,有什么想法

更新:

感谢@PriyankJ给了我这个主意,我设法找到了正确的查询,从而得到了想要的结果:

SELECT  **top 3** cte.FirstName ,B.JobTitle
FROM    **HumanResources.Employee B**
CROSS APPLY
        (
        SELECT  TOP 3 *
        FROM     **person.person A**
        WHERE   A.BusinessEntityID = B.BusinessEntityID
        ORDER BY
                A.BusinessEntityID DESC
        ) cte

更改(第一个查询与第二个查询之间的差异)被突出显示:)

4 个答案:

答案 0 :(得分:2)

我认为交叉应用左表必须为HumanResources.Employee才能获得相同的结果。

SELECT TOP 3
    cte.firstname
   ,A.jobtitle
FROM HumanResources.Employee A
CROSS APPLY (SELECT
        *
    FROM Person.Person B
    WHERE B.BusinessEntityID = A.BusinessEntityID) cte
ORDER BY cte.BusinessEntityID DESC

答案 1 :(得分:1)

所以你问'为什么'。这可能会有所帮助。

重要的是要更好地了解JOIN和CROSS APPLY的实际作用。

考虑以下架构:

DECLARE @Person as Table (BusinessEntityID int, firstname varchar(10))
DECLARE @Employee as Table (BusinessEntityID int, jobtitle varchar(10))

INSERT INTO @Person (BusinessEntityID, firstname) Values
(1,'Annie'), (2,'Brad'), (3,'Coraline'),  (4,'David')

INSERT INTO @Employee (BusinessEntityID, jobtitle) Values
(1,'Director'), (2,'Manager'), (3,'Analyst'), (4,'Gopher')

第一个查询

with cte as(
select *, ROW_NUMBER() OVER(ORDER BY businessentityid desc) AS Row#
from @Employee
)
Select A.firstname, B.jobtitle
from @Person A
inner join cte B on A.BusinessEntityID = B.BusinessEntityID and B.Row# <= 3

哪个返回此:

firstname  jobtitle
---------- ----------
Brad       Manager
Coraline   Analyst
David      Gopher

您的CTE被BusinessEntityID(降序)限制为前3个记录。所以安妮不在那。然后,我们执行内部联接,该联接返回两个组中与联接列匹配的所有记录。因此,Employee表中的Director掉了出来,我们的最终集合是3条记录。但是交叉申请在做什么?

Select A.firstname, cte.jobtitle
from @Person A
cross apply 
(
Select top 3 * 
from @Employee B
where B.BusinessEntityID= A.BusinessEntityID
order by businessentityid DESC
) cte

firstname  jobtitle
---------- ----------
Annie      Direcor
Brad       Manager
Coraline   Analyst
David      Gopher

这是不同的。 CROSS APPLY与联接列上的两个集合不匹配。 相反,它会评估左侧每一行的右侧。 Person中有四行,对于每一项,Cross Apply将从Employee中选择前3条记录,这些记录将与BusinessEntityID上的该行匹配(由于where子句)。这将给您4行。让我们稍微更改一下Employee表。

INSERT INTO @Employee (BusinessEntityID, jobtitle) Values 
(1,'Direcor'),(2,'Manager'),(3,'Analyst'),(4,'Gopher'),(4,'Blacksmith')

我们添加了具有重复实体ID的铁匠。我们得到什么?

加入逻辑

firstname  jobtitle
---------- ----------
Coraline   Analyst
David      Gopher
David      Blacksmith

交叉应用逻辑

firstname  jobtitle
---------- ----------
Annie      Direcor
Brad       Manager
Coraline   Analyst
David      Gopher
David      Blacksmith

我们看到,在加入的CTE中,重复的ID已将我们较小的ID之一从前3个BusinessEntityId列表中排除,而David在重复的ID处出现了两次。

在交叉应用中,我们有来自Person的四行,以及来自Employee的前三行,它们与person的每一行都匹配。在BusinessEntityID = 4的情况下,有两个匹配项,我们都得到了它们。

最重要的一点是,Cross apply在左侧的每一行的上下文中评估右侧。联接只是返回匹配的行。

如果您希望交叉联接查询模仿内部联接可以创建的相同“过滤”效果,则必须将要限制的表放在交叉联接的左侧。

;with cte as(
select *, ROW_NUMBER() OVER(ORDER BY businessentityid desc) AS Row#
from @Employee
)
Select A.firstname, B.jobtitle
from cte B
cross join @Person A 
where A.BusinessEntityID = B.BusinessEntityID and B.Row# <= 3



firstname  jobtitle
---------- ----------
David      Gopher
David      Blacksmith
Coraline   Analyst

答案 2 :(得分:0)

您需要的是“外部申请”。试试这个:

Select A.firstname, cte.jobtitle 
from Person.Person A
outer apply 
(
Select top 3 * 
    from HumanResources.Employee B
    where B.BusinessEntityID= A.BusinessEntityID
    order by businessentityid DESC
) cte

答案 3 :(得分:0)

最重要的是为什么要使用CROSS APPLYINNER JOIN

您可以通过这种方式尝试

Select A.firstname, cte.jobtitle 
from Person.Person A
cross apply 
(
Select * from
(
Select top 3 * 
from HumanResources.Employee B
order by businessentityid DESC
)B
where B.BusinessEntityID= A.BusinessEntityID
) cte

现在,您可以轻松了解为什么得到不同的结果。