我对使用CTE
ROW_NUMBER OVER PARTITION
UserID, BranchNumber, MemberDate
时添加条件的首选位置感到困惑。
我有一个包含以下列的表:
MemberStatus
和WITH 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。
答案 0 :(得分:1)
两者都是“正确的”,从某种意义上说它们会回复所要求的内容。 (2)提供更多记录,因为您在子查询(cte)中应用了额外条件(MemberStatus = 'Active'
)。所以记录MemberStatus不等于“Active”的地方不能有“RowNumber = 1”。 (1)不会在CTE中过滤这样的行,因此它可能返回带有RowNumber=1 and MemberStatus <> 'Active'
的记录[s],它通过在外部查询中应用条件而从最终结果集中删除。
答案 1 :(得分:0)
查询不同,所以我希望记录不同。
第一个查询说:
BranchNumber = 1
,MemberDate
和userId
上的分区MemberStatus is Active
第二个查询说:
activemember
获取所有BranchNumber = 1
条记录,按MemberDate
和partition 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'