SQL Server:与ROW_NUMBER()查询等效的交叉应用

时间:2018-10-11 15:31:19

标签: sql sql-server sql-server-2014

我试图找到一种不同的方式来使用ROW_NUMBER()来编写CROSS APPLY查询,以便可以比较性能。

在下面的简单示例中,创建了一个雇员表,插入了一些测试数据,并使用具有SELECT窗口函数的ROW_NUMBER()来查找每个部门中任职时间最长的雇员。

还有使用SELECT来写CROSS APPLY的另一种方法吗?

CREATE TABLE [dbo].[tblEmployee]
(
    [ID] [INT] NOT NULL,
    [DeptID] [TINYINT] NOT NULL,
    [EmpName] [VARCHAR](100) NOT NULL,
    [Tenure] [TINYINT] NOT NULL,

    CONSTRAINT [PK_tblEmployee] 
        PRIMARY KEY CLUSTERED ([ID] ASC)
) ON [PRIMARY]
GO

INSERT INTO dbo.tblEmployee (ID, DeptID, EmpName, Tenure) 
VALUES ('1', '1', 'John', 2),
       ('2', '1', 'Mary', 5),
       ('3', '2', 'Joe', 3),
       ('4', '3', 'Bill', 10),
       ('5', '2', 'Marilynn', 9),
       ('6', '3', 'Sue', 7);

SELECT 
    EmpName, DeptID, Tenure 
FROM  
    (SELECT 
         EmpName, DeptID, Tenure, 
         ROW_NUMBER() OVER(PARTITION BY DeptID ORDER BY Tenure DESC) TenureRank
     FROM 
         tblEmployee) e 
WHERE 
    e.TenureRank = 1
ORDER BY 
    DeptID

编辑:我不希望将CTE用作SELECT

的一部分

4 个答案:

答案 0 :(得分:0)

等效的for (int i=0; i <= 3; i++) { Serial.print("I value:");Serial.print(i); Serial.println(); Serial.print("guesser"); Serial.print(i+3-2*counter); Serial.println(); Serial.print("digits");Serial.print(digits[i+3-(2*counter)]); Serial.println(); if (digits[i+3-(2*counter)]==1) { digitalWrite(ledPins[i], HIGH); Serial.print("THIS BULB LIT UP:");Serial.print(i); } else { digitalWrite(ledPins[i], LOW); } counter=counter+1; delay(1000); } 为:

cross apply

您不想这样做,因为它的效率比select e.*, a.seqnum from tblEmployee e cross apply (select count(*) as seqnum from tblEmployee e2 where e2.deptid = e.deptid and (e2.tenure > e.tenure or e2.tenure = e.tenure and e2.id >= e.id ) ) a; 低得多。请注意使用row_number()进行比较以确保数字唯一。

答案 1 :(得分:0)

与扫描整个tblEmployee表相比,您可能有一个更好的部门ID来源:

SELECT a.* 
FROM (SELECT DISTINCT DeptID FROM tblEmployee) d
CROSS APPLY (
    SELECT TOP 1 EmpName, DeptID, Tenure
    FROM tblEmployee e
    WHERE e.DeptID = d.DeptID
    ORDER BY Tenure DESC
) a

该特定示例不太可能支持APPLY方法,因为您还需要设计源值。

在处理已经具有源数据的查询时,APPLY可能更有意义(例如,您也需要部门名称,因此自然而然地从想象中的tblDepartment表开始)。当您需要从多个地方获取此类信息时(在一个查询中有多个APPLY比ROW_NUMBER()要容易得多),或者当APPLY操作本身是一个更复杂的子查询时,它也可以做得很好。 ,在几个表格中查找。

答案 2 :(得分:0)

您实际上可以执行此操作,而无需使用CROSS APPLYROWNUM。您可以创建一个派生表,列出每个部门的最大任职期,然后将其加入基本员工表。使用CTE,您的查询将如下所示:

WITH 
    DeptWithMaxTenure AS
    (
        SELECT DeptID, Max(Tenure) AS MaxTenure
        FROM tblEmployee
        GROUP BY DeptID
    )
SELECT
    tblEmployee.EmpName,
    tblEmployee.DeptID,
    tblEmployee.Tenure
FROM tblEmployee
    INNER JOIN DeptWithMaxTenure ON
        DeptWithMaxTenure.DeptID = tblEmployee.DeptID
        AND DeptWithMaxTenure.MaxTenure = tblEmployee.Tenure

答案 3 :(得分:0)

我尝试过,它的速度是原始速度的4倍

SELECT A.EmpName, A.DeptID, A.Tenure FROM tblEmployee A 
               CROSS APPLY 
                    (SELECT TOP 1 B.ID FROM tblEmployee B 
                          WHERE B.DeptID = A.DeptID Order By Tenure Desc) CA
WHERE CA.ID = A.ID;