Ric*_*ley 7 sql-server common-table-expression
我正在努力找到关于我的CTE的正确逻辑.
一些背景资料:
系统中为具有销售角色的所有成员生成任务.这基本上会在我的Task
表中插入多条记录.任务表包括以下列:AssignedTo
和RequestedBy
- 其中AssignedTo
将有每个销售成员Id.目前所有销售人员都可以看到该任务,因为没有人声称它:
ApprovalStatusId EntityType EntityId AssignedTo RequestedBy
18 | FooBar | 281 | 4 | 6
18 | FooBar | 281 | 9 | 6
18 | FooBar | 281 | 17 | 6
18 | FooBar | 281 | 26 | 6
18 | FooBar | 281 | 39 | 6
Run Code Online (Sandbox Code Playgroud)
现在已经为每个销售人员生成了一个任务,其中一个任务无关紧要,谁可以对任务做出反应,这将改变AssignedTo
任务状态和任务状态:
ApprovalStatusId EntityType EntityId AssignedTo RequestedBy
18 | FooBar | 281 | 4 | 6
18 | FooBar | 281 | 9 | 6
18 | FooBar | 281 | 17 | 6
18 | FooBar | 281 | 26 | 6
18 | FooBar | 281 | 39 | 6
17 | FooBar | 281 | 26 | 6
1 | FooBar | 281 | 6 | 6
Run Code Online (Sandbox Code Playgroud)
从上表中可以看出,用户26对任务做出了反应并更改了状态.完成后,系统将任务重定向回原始请求,即用户6 - 状态也已更改以指示此操作.
问题:
我尝试过的:
解决#1:
;WITH cte AS
(
SELECT task.*, stat.Name AS StatusName,
ROW_NUMBER() OVER (PARTITION BY EntityId, EntityType ORDER BY ModifiedData DESC) AS rn
FROM dbo.Task task
INNER JOIN dbo.ApprovalStatus stat on task.ApprovalStatusId = stat.ApprovalStatusId
)
SELECT *
FROM cte
WHERE AssignedTo = @resourceId
AND StatusName like 'Pending%'
AND rn = 1
Run Code Online (Sandbox Code Playgroud)
因此,这段SQL的一个问题是AND rn = 1
,因为这是导致第1点引发问题的原因,但如果我删除它并且状态发生变化,它将无法获得最新的任务项.另一方面,它也导致了这个问题.
我也尝试将分区更改为:PARTITION BY EntityId, EntityType, AssignedTo ORDER BY ModifiedData DESC
,但问题是,rn
在大多数情况下,它会产生等于1的值,这将不会产生基于销售组的正确结果.
[更新]:
样本数据:
Comments InsertDate ModifiedData CommentUserId ApprovalStatusId EntityType EntityId TenantId AssignedTo RequestedBy
... | 2017-03-20 11:18:06.343| 2017-03-20 11:18:06.343| NULL | 18 | FooBar | 75 |7 |4 |42
... | 2017-03-20 11:18:06.343| 2017-03-20 11:18:06.343| NULL | 18 | FooBar | 75 |7 |6 |42
... | 2017-03-20 11:18:06.343| 2017-03-20 11:18:06.343| NULL | 18 | FooBar | 75 |7 |9 |42
... | 2017-03-20 11:18:06.343| 2017-03-20 11:18:06.343| NULL | 18 | FooBar | 75 |7 |17 |42
... | 2017-03-20 11:18:06.343| 2017-03-20 11:18:06.343| NULL | 18 | FooBar | 75 |7 |26 |42
... | 2017-03-20 11:18:06.343| 2017-03-20 11:18:06.343| NULL | 18 | FooBar | 75 |7 |39 |42
... | 2017-03-20 11:18:06.343| 2017-03-20 11:18:06.343| NULL | 18 | FooBar | 75 |7 |67 |42
... | 2017-03-20 11:18:06.343| 2017-03-20 11:18:06.343| NULL | 18 | FooBar | 75 |7 |10073 |42
... | 2017-03-20 11:18:06.343| 2017-03-20 11:18:06.343| NULL | 18 | FooBar | 75 |7 |10164 |42
Run Code Online (Sandbox Code Playgroud)
期望的输出:
声明该任务的销售用户应该是唯一可以看到它的人.换句话说,销售用户应该能够看到此记录(在第二个表示例中可见) - 所有其他销售用户应该看不到任何内容
17 | FooBar | 281 | 26 | 6
Run Code Online (Sandbox Code Playgroud)
如果你展示了你想要的结果,你的问题会更好,但我认为你可能想要做的是考虑使用ranking
除 之外的不同窗口函数row_number()
,例如dense_rank()
;WITH cte AS
(
SELECT task.*, stat.Name AS StatusName,
dense_rank() OVER (PARTITION BY EntityId, EntityType ORDER BY ModifiedData DESC) AS dr
FROM dbo.Task task
INNER JOIN dbo.ApprovalStatus stat on task.ApprovalStatusId = stat.ApprovalStatusId
)
SELECT *
FROM cte
WHERE AssignedTo = @resourceId
AND StatusName like 'Pending%'
AND dr = 1
Run Code Online (Sandbox Code Playgroud)
当多条记录最初插入到task
表中时,cte 返回的不是:
+------------------+------------+----------+------------+-------------+----+
| ApprovalStatusId | EntityType | EntityId | AssignedTo | RequestedBy | rn |
+------------------+------------+----------+------------+-------------+----+
| 18 | FooBar | 281 | 4 | 6 | 1 |
| 18 | FooBar | 281 | 9 | 6 | 2 |
| 18 | FooBar | 281 | 17 | 6 | 3 |
| 18 | FooBar | 281 | 26 | 6 | 4 |
| 18 | FooBar | 281 | 39 | 6 | 5 |
+------------------+------------+----------+------------+-------------+----+
Run Code Online (Sandbox Code Playgroud)
它将返回:
+------------------+------------+----------+------------+-------------+----+
| ApprovalStatusId | EntityType | EntityId | AssignedTo | RequestedBy | dr |
+------------------+------------+----------+------------+-------------+----+
| 18 | FooBar | 281 | 4 | 6 | 1 |
| 18 | FooBar | 281 | 9 | 6 | 1 |
| 18 | FooBar | 281 | 17 | 6 | 1 |
| 18 | FooBar | 281 | 26 | 6 | 1 |
| 18 | FooBar | 281 | 39 | 6 | 1 |
+------------------+------------+----------+------------+-------------+----+
Run Code Online (Sandbox Code Playgroud)
这样就可以解决问题#1,即只有一个用户看到待处理的任务。