使用窗口函数获取总数

Posted

技术标签:

【中文标题】使用窗口函数获取总数【英文标题】:Get total count using a window function 【发布时间】:2016-09-16 19:54:37 【问题描述】:

嘿,这就是我目前的查询:

WITH LIMIT AS
        (SELECT 
             U.userID
            ,U.username
            ,U.fname    
            ,U.mname    
            ,U.lname    
            ,U.email    
            ,U.active 
            ,S.sName
            ,S.sID
            ,T.[value]
            ,T.trackingNumberID
            ,SU.primaryLocation
            ,row_number() OVER (ORDER BY U.userid) AS RN 
            ,COUNT(*) OVER (ORDER BY U.userid) AS CNT 
            ,UR.roleID
        FROM 
            [---].[dbo].[tblUsers]                          AS U
        LEFT OUTER JOIN [---].[dbo].[tblTrackingNumbers]    AS T
            ON T.userID = U.userID
        LEFT OUTER JOIN [---].[dbo].[tblSU]                 AS SU
            ON U.userID = SU.userID
        LEFT OUTER JOIN [---].[dbo].[tblS]                  AS S
            ON SU.sID = S.sID 
        LEFT OUTER JOIN [---].[dbo].[tblUserRoles]          AS UR 
            ON UR.userID = U.userID
        LEFT OUTER JOIN [---].[dbo].[tblRoles]              AS R 
            ON UR.roleID = R.roleID
        WHERE 
            U.active = 1 
        AND 
            SU.primaryLocation = 1
        AND 
            SU.active = 1 
        AND 
                U.orgID = 1
            AND 
                S.ID = 35 
            AND U.userID IN (SELECT userID 
                              FROM [---].[dbo].[tblSU] AS SU 
                              INNER JOIN [].[dbo].[tblS] AS S 
                                 ON S.sID = SU.sID 
                              WHERE 
                                 SU.active = 1 
                              AND 
                                 S.sID = 35)
) SELECT * FROM LIMIT WHERE RN Between 0 AND 10000

正如您在上面的查询中看到的那样,我正在尝试 COUNT(*) OVER (ORDER BY U.userid) AS CNT 这给了我与 RN 相同的计数.

我需要的是记录总数这将带回(842行)

【问题讨论】:

只做 Count(*) 并且不要对其进行分区。这不应该是你需要的吗? 哈就是@a_horse_with_no_name。请将其作为官方答案,以便我给予您信任。 您是否使用 RN 只是为了限制少于 1000 行?请先使用 Top 或 Fetch... 更快。 【参考方案1】:

COUNT(*) OVER (ORDER BY U.userid) AS CNT 计算“运行计数” - 直到“那个”行的计数。如果要计算完整结果中的所有行,请使用不带order by 的窗口函数

COUNT(*) OVER () AS CNT

【讨论】:

【参考方案2】:

这可能听起来很奇怪,但我发现对于大型表,如果您将计数选择到变量中,然后选择记录并添加变量,您可以获得更好的性能。当表变得太大时,带有 count(*) over() 的东西会导致性能下降。

DECLARE @RecordCount INT
SELECT  @RecordCount = COUNT(*)
FROM    [---].[dbo].[tblUsers] AS U
        LEFT OUTER JOIN [---].[dbo].[tblTrackingNumbers] AS T ON T.userID = U.userID
        LEFT OUTER JOIN [---].[dbo].[tblSU] AS SU ON U.userID = SU.userID
        LEFT OUTER JOIN [---].[dbo].[tblS] AS S ON SU.sID = S.sID
        LEFT OUTER JOIN [---].[dbo].[tblUserRoles] AS UR ON UR.userID = U.userID
        LEFT OUTER JOIN [---].[dbo].[tblRoles] AS R ON UR.roleID = R.roleID
WHERE   U.active = 1
        AND SU.primaryLocation = 1
        AND SU.active = 1
        AND U.orgID = 1
        AND S.ID = 35
        AND U.userID IN (SELECT userID
                         FROM   [---].[dbo].[tblSU] AS SU
                                INNER JOIN [].[dbo].[tblS] AS S ON S.sID = SU.sID
                         WHERE  SU.active = 1
                                AND S.sID = 35)

SELECT  U.userID,
        U.username,
        U.fname,
        U.mname,
        U.lname,
        U.email,
        U.active,
        S.sName,
        S.sID,
        T.[value],
        T.trackingNumberID,
        SU.primaryLocation,
        @RecordCount AS CNT,
        UR.roleID
FROM    [---].[dbo].[tblUsers] AS U
        LEFT OUTER JOIN [---].[dbo].[tblTrackingNumbers] AS T ON T.userID = U.userID
        LEFT OUTER JOIN [---].[dbo].[tblSU] AS SU ON U.userID = SU.userID
        LEFT OUTER JOIN [---].[dbo].[tblS] AS S ON SU.sID = S.sID
        LEFT OUTER JOIN [---].[dbo].[tblUserRoles] AS UR ON UR.userID = U.userID
        LEFT OUTER JOIN [---].[dbo].[tblRoles] AS R ON UR.roleID = R.roleID
WHERE   U.active = 1
        AND SU.primaryLocation = 1
        AND SU.active = 1
        AND U.orgID = 1
        AND S.ID = 35
        AND U.userID IN (SELECT userID
                         FROM   [---].[dbo].[tblSU] AS SU
                                INNER JOIN [].[dbo].[tblS] AS S ON S.sID = SU.sID
                         WHERE  SU.active = 1
                                AND S.sID = 35)
ORDER BY U.userID
OFFSET 0 ROWS FETCH NEXT 10000 ROWS ONLY

【讨论】:

以上是关于使用窗口函数获取总数的主要内容,如果未能解决你的问题,请参考以下文章

如何计算具有窗口函数的过滤器的总数?

SQL Server 使用窗口函数计算 AVG()

如何使用窗口函数“求和(DISTINCT <column>)OVER()”?

使用窗口函数在 Impala 中的总计列

获取窗口句柄

获取窗口句柄