TSQL在同一列A上放置相同的等级/行号,但一旦A列更改就会增加

Posted

技术标签:

【中文标题】TSQL在同一列A上放置相同的等级/行号,但一旦A列更改就会增加【英文标题】:TSQL Put same rank/row number on same column A but increment once column A changes 【发布时间】:2017-02-08 06:20:18 【问题描述】:

我有这张表,我想将排名/行号放入具有以下条件的行

    相同的 IO 将具有相同的等级/行号 一旦下一行的 IO 与上一行不同,排名/行号就会增加。

表格按 AccessDate 然后 AccessTime 排序并按 UserID 分组

我正在使用此查询,但输出不是我想要的。

SELECT
    ATTCHECKINOUT.UserID,
    AccessDate = CAST(CheckTime as date),
    AccessTime = CAST(CheckTime as time),
    CheckType, 
    Ranking = DENSE_RANK() over(partition by ATTCHECKINOUT.UserID, CAST(CheckTime as date) order by CheckType)
FROM ATTCHECKINOUT INNER JOIN ATTUSER ON ATTCHECKINOUT.UserID=ATTUSER.UserID   
WHERE CheckTime BETWEEN '1/6/2017' AND '1/10/2017' AND ATTUSER.BadgeNumber = 10311
ORDER BY ATTCHECKINOUT.UserID, CheckTime

查询的输出

UserID |AccessDate |AccessTime |IO |Ranking
8394   |2017-01-06 |11:24:10   |I  |1
8394   |2017-01-06 |11:24:15   |I  |1
8394   |2017-01-06 |13:05:13   |O  |2
8394   |2017-01-06 |13:05:18   |O  |2
8394   |2017-01-06 |13:34:17   |I  |1
8394   |2017-01-06 |13:34:20   |I  |1
8394   |2017-01-06 |20:35:01   |O  |2
8394   |2017-01-06 |20:35:05   |O  |2
8394   |2017-01-07 |10:59:49   |I  |1
8394   |2017-01-07 |10:59:52   |I  |1
8394   |2017-01-07 |17:02:54   |O  |2
8394   |2017-01-07 |17:29:39   |I  |1
8394   |2017-01-07 |17:29:43   |I  |1
8394   |2017-01-07 |20:13:02   |O  |2
8394   |2017-01-07 |20:13:05   |O  |2
8394   |2017-01-09 |08:32:38   |I  |1
8394   |2017-01-09 |08:32:45   |I  |1
8394   |2017-01-09 |20:02:52   |O  |2
8394   |2017-01-09 |20:02:55   |O  |2

我希望输出是这样的

UserID |AccessDate |AccessTime |IO |Ranking
8394   |2017-01-06 |11:24:10   |I  |1
8394   |2017-01-06 |11:24:15   |I  |1
8394   |2017-01-06 |13:05:13   |O  |2
8394   |2017-01-06 |13:05:18   |O  |2
8394   |2017-01-06 |13:34:17   |I  |3
8394   |2017-01-06 |13:34:20   |I  |3
8394   |2017-01-06 |20:35:01   |O  |4
8394   |2017-01-06 |20:35:05   |O  |4
8394   |2017-01-07 |10:59:49   |I  |1
8394   |2017-01-07 |10:59:52   |I  |1
8394   |2017-01-07 |17:02:54   |O  |2
8394   |2017-01-07 |17:29:39   |I  |3
8394   |2017-01-07 |17:29:43   |I  |3
8394   |2017-01-07 |20:13:02   |O  |4
8394   |2017-01-07 |20:13:05   |O  |4
8394   |2017-01-09 |08:32:38   |I  |1
8394   |2017-01-09 |08:32:45   |I  |1
8394   |2017-01-09 |20:02:52   |O  |2
8394   |2017-01-09 |20:02:55   |O  |2

【问题讨论】:

这个链接会帮助你***.com/questions/41949621/… sql 2008没有滞后功能 有多个带有/不带有滞后功能的答案...您是否检查过第二个答案(带有递归 cte)???? 是的,这就是我用来解决问题的方法。谢谢 看起来像gaps-and-islands... 是否要重新开始对每个UserIDAccessDate 进行排名? 【参考方案1】:

我已使用您的查询结果集的输出作为输入。并编写查询以获得预期的结果集。您必须通过查看以下查询来更改您的 order by 子句与 dense_rank 函数。

SELECT UserID,
       [AccessDate],
       [AccessTime],
       [IO],
       Dense_rank()
         OVER(
           partition BY UserID, [AccessDate]
           ORDER BY userid, [AccessDate], Datepart(hour, [AccessTime]), Datepart(minute, [AccessTime]),[IO]) Ranking
FROM   #table1 -- this contains result set of your output query

【讨论】:

问题是当小时和分钟部分对于相同的IO不同时,排名也会不同,导致输出不正确......【参考方案2】:

有趣的问题。我已经玩了一点,这就是我想出的。这不是我制作过的最优雅的东西,但似乎做对了。我正在使用表变量@t 来保存ATTCHECKINOUT 表中的值:

-- prepare test data
-- note: added some additional rows to test correctness

declare @t table (
    UserID int not null,
    CheckTime datetime not null,
    CheckType nvarchar(1) not null
)

insert into @t (UserID, CheckTime, CheckType) 
values
    (8394   ,'2017-01-06 11:24:10'   ,'I'), (8394   ,'2017-01-06 11:24:15'   ,'I'), 
    (8394   ,'2017-01-06 13:05:13'   ,'O'), (8394   ,'2017-01-06 13:05:18'   ,'O'),
    (8394   ,'2017-01-06 13:34:17'   ,'I'), (8394   ,'2017-01-06 13:34:20'   ,'I'),
    (8394   ,'2017-01-06 20:35:01'   ,'O'), (8394   ,'2017-01-06 20:35:05'   ,'O'),
    (8394   ,'2017-01-07 10:59:49'   ,'I'), (8394   ,'2017-01-07 10:59:52'   ,'I'),
    (8394   ,'2017-01-07 17:02:54'   ,'O'), (8394   ,'2017-01-07 17:29:39'   ,'I'),
    (8394   ,'2017-01-07 17:29:43'   ,'I'), (8394   ,'2017-01-07 20:13:02'   ,'O'),
    (8394   ,'2017-01-07 20:13:05'   ,'O'), (8394   ,'2017-01-07 20:14:08'   ,'O'),
    (8394   ,'2017-01-07 23:14:08'   ,'O'), (8394   ,'2017-01-09 08:32:38'   ,'I'),
    (8394   ,'2017-01-09 08:32:45'   ,'I'), (8394   ,'2017-01-09 20:02:52'   ,'O'),
    (8394   ,'2017-01-09 20:02:55'   ,'O'), (8395   ,'2017-01-06 11:24:10'   ,'I'),
    (8395   ,'2017-01-06 11:24:15'   ,'I'), (8395   ,'2017-01-06 13:05:13'   ,'O'),
    (8395   ,'2017-01-06 13:05:18'   ,'O'), (8395   ,'2017-01-06 13:09:32'   ,'O'),
    (8395   ,'2017-01-06 13:34:17'   ,'I'), (8395   ,'2017-01-06 13:34:20'   ,'I')

-- produce output

select UserID,
    cast(CheckTime as date) as AccessDate,
    cast(CheckTime as time) as AccessTime,
    CheckType,
    dense_rank() over (order by groupKey) as [rank]
from (
    select UserID, CheckTime, CheckType,
        max(newGroup) over (order by UserId, CheckTime, CheckType ROWS UNBOUNDED PRECEDING ) as groupKey
    from (
        select UserId,
            CheckTime,
            CheckType,
            case 
                when CheckType = lag(CheckType, 1, '') over (order by UserId, CheckTime) 
            then 
                null 
            else 
                row_number() over (order by UserId, CheckTime, CheckType) 
            end as newGroup
        from @t
        where CheckTime >= '2017-01-06 13:05:17.000' -- note where clause here
            and UserID = 8394                        -- note where clause here
    ) as innerSub
) as outerSub
order by UserId, CheckTime, CheckType

输出:

+--------+------------+------------------+-----------+------+
| UserID | AccessDate |    AccessTime    | CheckType | rank |
+--------+------------+------------------+-----------+------+
|   8394 | 2017-01-06 | 13:05:18.0000000 | O         |    1 |
|   8394 | 2017-01-06 | 13:34:17.0000000 | I         |    2 |
|   8394 | 2017-01-06 | 13:34:20.0000000 | I         |    2 |
|   8394 | 2017-01-06 | 20:35:01.0000000 | O         |    3 |
|   8394 | 2017-01-06 | 20:35:05.0000000 | O         |    3 |
|   8394 | 2017-01-07 | 10:59:49.0000000 | I         |    4 |
|   8394 | 2017-01-07 | 10:59:52.0000000 | I         |    4 |
|   8394 | 2017-01-07 | 17:02:54.0000000 | O         |    5 |
|   8394 | 2017-01-07 | 17:29:39.0000000 | I         |    6 |
|   8394 | 2017-01-07 | 17:29:43.0000000 | I         |    6 |
|   8394 | 2017-01-07 | 20:13:02.0000000 | O         |    7 |
|   8394 | 2017-01-07 | 20:13:05.0000000 | O         |    7 |
|   8394 | 2017-01-07 | 20:14:08.0000000 | O         |    7 |
|   8394 | 2017-01-07 | 23:14:08.0000000 | O         |    7 |
|   8394 | 2017-01-09 | 08:32:38.0000000 | I         |    8 |
|   8394 | 2017-01-09 | 08:32:45.0000000 | I         |    8 |
|   8394 | 2017-01-09 | 20:02:52.0000000 | O         |    9 |
|   8394 | 2017-01-09 | 20:02:55.0000000 | O         |    9 |
+--------+------------+------------------+-----------+------+

编辑:这是一个适用于 SQL Server 2008 的新版本。准备测试数据与以前相同。

;with cte as (
    select UserID, CheckTime, CheckType,
        (case when sub.CheckType != sub.PrevCheckType then sub.RowNum else null end) as Indicator
    from (
        select UserID, CheckTime, CheckType, 
            ISNULL((
                select top 1 CheckType 
                from @t as innerT
                where t.UserID = innerT.UserID 
                    and t.CheckTime > innerT.CheckTime 
                order by UserID, CheckTime desc), '') as PrevCheckType
            , row_number() over (order by UserID, CheckTime, CheckType) as RowNum
        from @t as t
        where CheckTime >= '2017-01-06 13:05:17.000' -- note where clause here
            and UserID = 8394                        -- note where clause here
    ) sub
)
select UserID,
    cast(CheckTime as date) as AccessDate, 
    cast(CheckTime as time) as AccessTime, 
    CheckType,
    dense_rank() over (partition by UserID order by UserID, ISNULL(Indicator, (select top 1 Indicator from cte innerCte where outerCte.UserID = innerCte.UserID and outerCte.CheckTime > innerCte.CheckTime and Indicator is not null order by UserID, CheckTime desc))) as [Rank]
from cte outerCte
order by UserID, CheckTime, CheckType

这个版本可以很容易地修改为在 Sql Server 2005 上也可以工作。只需修复 prepare test data 部分,不要在输出中使用 datetime 转换。 p>

【讨论】:

感谢回复可惜只用sql server 2008,这个版本的sql没有滞后功能 @DennisLim 你注意到我为 Sql Server 2008 添加了一个单独的示例吗?

以上是关于TSQL在同一列A上放置相同的等级/行号,但一旦A列更改就会增加的主要内容,如果未能解决你的问题,请参考以下文章

更新列问题tsql

在同一列/行中查找第一个空单元格

n皇后问题

codevs 1295 N皇后问题

化工行业等级品管理

n皇后问题