使用Row_number在CTE中使用Where子句设置条件的位置

时间:2013-12-21 19:20:46

标签: sql-server tsql

我对使用CTE ROW_NUMBER OVER PARTITION UserID, BranchNumber, MemberDate时添加条件的首选位置感到困惑。

我有一个包含以下列的表:

MemberStatusWITH CTE AS ( SELECT * ,ROW_NUMBER() OVER (PARTITION BY UserID ORDER BY [MemberDate] DESC) AS RowNumber FROM MemberTable WHERE BranchNumber = '01' ) SELECT * FROM CTE WHERE RowNumber = 1 AND MemberStatus = 'Active'

注意:会员可以在不同的位置拥有多个会员资格:

以下代码给了我少一条记录:17069

WITH CTE AS
(
SELECT 
 *
,ROW_NUMBER() OVER (PARTITION BY UserID ORDER BY [MemberDate] DESC) AS RowNumber 

FROM MemberTable 

WHERE BranchNumber = '01' AND MemberStatus = 'Active'
) 
SELECT * FROM CTE WHERE RowNumber = 1

以下代码提供了一条额外的记录:17070

{{1}}

我很困惑为什么差异和哪种方式正确?

正确的记录数量是19000。

4 个答案:

答案 0 :(得分:1)

两者都是“正确的”,从某种意义上说它们会回复所要求的内容。 (2)提供更多记录,因为您在子查询(cte)中应用了额外条件(MemberStatus = 'Active')。所以记录MemberStatus不等于“Active”的地方不能有“RowNumber = 1”。 (1)不会在CTE中过滤这样的行,因此它可能返回带有RowNumber=1 and MemberStatus <> 'Active'的记录[s],它通过在外部查询中应用条件而从最终结果集中删除。

答案 1 :(得分:0)

查询不同,所以我希望记录不同。

第一个查询说:

  • 获取所有记录BranchNumber = 1MemberDateuserId上的分区
  • 然后,从该结果集中,仅在MemberStatus is Active
  • 时为每位用户提供第一条记录

第二个查询说:

  • activemember获取所有BranchNumber = 1条记录,按MemberDatepartition on userId
  • 排序
  • 然后,从上面的结果中,找到第一个实例。

因此,第一个结果集可能是从用户获取最新记录,不活动或不活动,然后过滤掉不活动的记录。第二个只返回活动记录,所以我期待更多。

答案 2 :(得分:0)

ROW_NUMBER之后评估WHERE。让我们通过将两者分开来使其更直观:

WITH CTE1 AS
(
SELECT 
 *

FROM MemberTable 

WHERE BranchNumber = '01' AND MemberStatus = 'Active'
) 
, CTE2 AS (
 SELECT *, ROW_NUMBER() OVER (PARTITION BY UserID ORDER BY [MemberDate] DESC) AS RowNumber 
  FROM CTE1
)
SELECT * FROM CTE2 WHERE RowNumber = 1

我认为现在很清楚你需要先应用过滤器。将CTE视为虚拟表。您可以通过将最终选择更改为SELECT * FROM CTE1来进行调试。看看返回的内容。

答案 3 :(得分:0)

由于您已经提到“某个成员可以在不同位置拥有多个成员资格”,请尝试按"BranchNumber"对其进行分区,看看它是否为您提供了所需的结果。

您正在这样做,它返回任何位置的最后成员资格开始日期,如果您按BranchNumber分区,它将返回每个分支编号的每个用户的最后成员资格开始日期,尝试这样的事情

;WITH  
CTE 
AS
  (
   SELECT *
   ,ROW_NUMBER() OVER (PARTITION BY UserID, BranchNumber ORDER BY [MemberDate] DESC)  
                                                                   AS RowNumber 
    FROM MemberTable 

  ) 
SELECT * FROM CTE
WHERE RowNumber = 1 AND MemberStatus = 'Active'