Sql server 在带有Rownumber的CTE中,使用Where子句设置条件的位置
当使用Sql server 在带有Rownumber的CTE中,使用Where子句设置条件的位置,sql-server,tsql,Sql Server,Tsql,当使用CTE和ROW\u NUMBER OVER PARTITION时,我有点困惑,在哪里可以添加条件 我有一个包含以下列的表: UserID、BranchNumber、MemberDate和MemberStatus 注意:一个成员可以在不同的位置拥有多个成员身份: 下面的代码让我少了一条记录:17069 以下代码提供了一条附加记录:17070 我只是不明白为什么会有这样的区别,哪种方式才是正确的 正确的记录数量是19000条。从某种意义上说,这两条记录都是“正确的”,它们都返回了所请求的内容。
CTE
和ROW\u NUMBER OVER PARTITION
时,我有点困惑,在哪里可以添加条件
我有一个包含以下列的表:
UserID、BranchNumber、MemberDate
和MemberStatus
注意:一个成员可以在不同的位置拥有多个成员身份:
下面的代码让我少了一条记录:17069
以下代码提供了一条附加记录:17070
我只是不明白为什么会有这样的区别,哪种方式才是正确的
正确的记录数量是19000条。从某种意义上说,这两条记录都是“正确的”,它们都返回了所请求的内容。(2) 提供更多记录,因为您在子查询(cte)中应用了额外条件(
MemberStatus='Active'
)。因此,MemberStatus不等于“Active”的记录不能有“RowNumber=1”。(1) 不过滤CTE中的此类行,因此它可能返回RowNumber=1和MemberStatus“Active”
的记录,这些记录通过在外部查询中应用条件从最终结果集中删除。查询是不同的,因此我希望记录是不同的
第一个问题是:
- 获取
的所有记录,按BranchNumber=1
和MemberDate
userId上的分区排序
- 然后,从该结果集中,仅当
MemberStatus处于活动状态时,为每个用户获取1st记录
- 从
获取所有BranchNumber=1
记录,按用户ID上的activemember
和MemberDate
分区排序
- 然后,根据上面的结果,给我第一个实例
因此,第一个结果集可能是从用户处获取最新的记录,不管是非活动记录还是非活动记录,然后过滤掉非活动记录。第二个将只返回活动记录,因此我希望得到更多。在
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视为虚拟表。您可以通过从CTE1将最终选择更改为
select*来调试此功能。只需查看返回的内容。因为您提到了“一个成员可以在不同的位置拥有多个成员身份”,请尝试将其按“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'
没有更好的地方可以添加条件。只有一个正确的地方。这取决于你需要什么。我不清楚你需要什么。您想要第一个活动的项目,还是想要第一个活动的项目?我想要所有最新的活动的记录和分支01
。我想说,在CTE中使用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
;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'