CTE行号分区

时间:2017-03-20 11:01:49

标签: sql-server common-table-expression

我很难找到关于我的CTE的正确逻辑。

一些背景信息:

系统中为具有销售角色的所有成员生成任务。这基本上将多个记录插入到我的Task表中。 “任务”表格包含以下列:AssignedToRequestedBy - 其中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

现在已经为每个销售人员生成了一个任务,其中一个人无关紧要,可以对任务作出反应,这将改变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

从上表中可以看出,用户26对任务做出了反应并更改了状态。完成后,系统将任务重定向回原始请求,即用户6 - 状态也已更改以指示此操作。

的问题:

  1. 目前,只有一个用户(Id 4)看到分配给所有销售用户的任务
  2. 我尝试了什么:

    解决#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
    

    因此,这段SQL的问题之一是AND rn = 1,因为这是导致第1点引发问题的原因,但是如果我删除它并且状态发生变化,它将无法获得最新任务项目。另一方面,它也会导致这个问题。

    我还尝试将分区更改为:PARTITION BY EntityId, EntityType, AssignedTo ORDER BY ModifiedData DESC,但问题是,在大多数情况下,它会产生一个等于1的rn,这将不会产生基于销售组的正确结果。

    [更新]:

    任务表定义: enter image description here

    示例数据:

    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
    

    期望的输出:

    声明任务的销售用户应该是唯一可以看到它的人。换句话说,销售用户应该能够看到此记录(在第二个表示例中可见) - 所有其他销售用户都应该看不到任何内容

    17               | FooBar       | 281       | 26        | 6
    

1 个答案:

答案 0 :(得分:2)

如果您展示了所需的结果,那么您的问题会更好,但我认为您可能想要考虑使用row_number()以外的其他ranking窗口函数,例如{{3} }

;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

当多个记录最初插入到您的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 |
+------------------+------------+----------+------------+-------------+----+

它将返回:

+------------------+------------+----------+------------+-------------+----+
| 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 |
+------------------+------------+----------+------------+-------------+----+

这样可以解决问题#1,其中只有一个用户正在看待挂起的任务。