【问题标题】:SSMS SQL Row_Number incorrect sortSSMS SQL Row_Number 排序不正确
【发布时间】:2020-11-05 00:05:06
【问题描述】:

我正在尝试按 USID 排序,然后按日期排序并重新启动 USID 上的行号,已使用。但是由于某种原因,日期的顺序不正确,所以行编号没有做我需要的。

目前这是我的代码给我的:

USID | Date   | Utilized | RowNumber
123  | 1/1/19 | T        | 1
123  | 1/2/19 | T        | 2
123  | 1/3/19 | T        | 3
123  | 1/19/19| T        | 4
123  | 1/20/19| T        | 5
123  | 1/21/19| T        | 6
123  | 1/4/19 | F        | 1
123  | 1/5/19 | F        | 2
123  | 1/6/19 | F        | 3
123  | 1/7/19 | F        | 4
123  | 1/8/19 | F        | 5
123  | 1/9/19 | F        | 6
125  | 1/1/19 | T        | 1
125  | 1/2/19 | T        | 2
125  | 1/3/19 | T        | 3
125  | 1/10/19| T        | 4
125  | 1/11/19| T        | 5
125  | 1/12/19| T        | 6
125  | 1/4/19 | F        | 1
125  | 1/5/19 | F        | 2
125  | 1/6/19 | F        | 3
125  | 1/7/19 | F        | 4
125  | 1/8/19 | F        | 5
125  | 1/9/19 | F        | 6

但是我希望它看起来像:

USID | Date   | Utilized | RowNumber
123  | 1/1/19 | T        | 1
123  | 1/2/19 | T        | 2
123  | 1/3/19 | T        | 3
123  | 1/4/19 | F        | 1
123  | 1/5/19 | F        | 2
123  | 1/6/19 | F        | 3
123  | 1/7/19 | F        | 4
123  | 1/8/19 | F        | 5
123  | 1/9/19 | F        | 6
123  | 1/19/19| T        | 1
123  | 1/20/19| T        | 2
123  | 1/21/19| T        | 3
125  | 1/1/19 | T        | 1
125  | 1/2/19 | T        | 2
125  | 1/3/19 | T        | 3
125  | 1/4/19 | F        | 1
125  | 1/5/19 | F        | 2
125  | 1/6/19 | F        | 3
125  | 1/7/19 | F        | 4
125  | 1/8/19 | F        | 5
125  | 1/9/19 | F        | 6
125  | 1/10/19| T        | 1
125  | 1/11/19| T        | 2
125  | 1/12/19| T        | 3

这是我目前所拥有的:

select 
   USID, cast(Date as datetime) as Date, Utilized, 
     ROW_NUMBER() OVER(PARTITION BY USID, Utilized 
                       ORDER BY USID, cast(Date as datetime) ASC, Utilized)
from vps_time_FullyUtilized

我哪里错了?

【问题讨论】:

  • 看来您想统计组值的集群,并在集群更改值时重新开始计数。
  • cast(Date as datetime) 的意义何在?日期不需要铸造。它们也不使用两位数年份显示。如果您将日期存储为字符串,更糟糕的是,存储为两位数的年份,您将遇到一个重大错误。就在劳埃德和瑞银因此类 Y2K 黑客事件而崩溃的那一年
  • 顺便说一句,通过存储字符串而不是日期,您实际上正在使用更多存储空间。 date 类型只占用 3 个字节。修复表架构。 PS SSMS 只是一个客户端工具,而不是数据库服务器。它不影响服务器的排序方式
  • 它们在源系统中被存储为日期,但为了让两个表在这个视图中运行,它们映射为 varchar。在这种情况下,我真的只需要弄清楚如何正确排序
  • 你不能仅仅使用ROW_NUMBER来解决这个问题。您需要找到具有相同 USID 和 Utilized 值的“岛屿”。这个问题的实际名称是gaps and islands。您可以使用LEADLAG 函数在结果集中查找下一个Utilized 值并检测孤岛何时结束

标签: sql-server tsql


【解决方案1】:

这是一种差距和孤岛解决方案。 SQL Fiddle

MS SQL Server 2017 架构设置

CREATE TABLE T(USID INT, Date DATETIME, Utilized NVARCHAR(10))
    INSERT INTO T VALUES
    (123,  '1/1/19',  'T'),
    (123,  '1/2/19',  'T'),
    (123,  '1/3/19',  'T'),
    (123,  '1/4/19',  'F'),
    (123,  '1/5/19',  'F'),
    (123,  '1/6/19',  'F'),
    (123,  '1/7/19',  'F'),
    (123,  '1/8/19',  'F'),
    (123,  '1/9/19',  'F'),
    (123,  '1/19/19', 'T'),
    (123,  '1/20/19', 'T'),
    (123,  '1/21/19', 'T'),
    
    (223,  '1/1/19',  'T'),
    (223,  '1/2/19',  'T'),
    (223,  '1/3/19',  'T'),
    (223,  '1/4/19',  'F'),
    (223,  '1/5/19',  'F'),
    (223,  '1/6/19',  'F'),
    (223,  '1/7/19',  'F'),
    (223,  '1/8/19',  'F'),
    (223,  '1/9/19',  'F'),
    (223,  '1/19/19', 'T'),
    (223,  '1/20/19', 'T'),
    (223,  '1/21/19', 'T')

查询 1

WITH DataWithEndBoundries AS
(
    SELECT 
        USID,Date,Utilized,
        --Mark your groups here
        IsNewGroup = CASE WHEN ISNULL(LAG(Utilized) OVER (ORDER BY USID,Date),Utilized)<>Utilized THEN 1 ELSE 0 END
    FROM 
        T
)
,VirtualGroup AS
(
    SELECT 
        *,
        --This serialzes the marked groups into clusters 
        VirtualGroupID = SUM(IsNewGroup) OVER (ORDER BY USID, Date ROWS UNBOUNDED PRECEDING)
    FROM 
        DataWithEndBoundries
)
SELECT 
    USID, Date, Utilized,
    --Now you can row number agianst the Virtualized value
    RowNumber = ROW_NUMBER() OVER (PARTITION BY USID, VirtualGroupID ORDER BY Date)
FROM 
    VirtualGroup
ORDER BY 
    USID,Date

Results

| USID |                 Date | Utilized | RowNumber |
|------|----------------------|----------|-----------|
|  123 | 2019-01-01T00:00:00Z |        T |         1 |
|  123 | 2019-01-02T00:00:00Z |        T |         2 |
|  123 | 2019-01-03T00:00:00Z |        T |         3 |
|  123 | 2019-01-04T00:00:00Z |        F |         1 |
|  123 | 2019-01-05T00:00:00Z |        F |         2 |
|  123 | 2019-01-06T00:00:00Z |        F |         3 |
|  123 | 2019-01-07T00:00:00Z |        F |         4 |
|  123 | 2019-01-08T00:00:00Z |        F |         5 |
|  123 | 2019-01-09T00:00:00Z |        F |         6 |
|  123 | 2019-01-19T00:00:00Z |        T |         1 |
|  123 | 2019-01-20T00:00:00Z |        T |         2 |
|  123 | 2019-01-21T00:00:00Z |        T |         3 |
|  223 | 2019-01-01T00:00:00Z |        T |         1 |
|  223 | 2019-01-02T00:00:00Z |        T |         2 |
|  223 | 2019-01-03T00:00:00Z |        T |         3 |
|  223 | 2019-01-04T00:00:00Z |        F |         1 |
|  223 | 2019-01-05T00:00:00Z |        F |         2 |
|  223 | 2019-01-06T00:00:00Z |        F |         3 |
|  223 | 2019-01-07T00:00:00Z |        F |         4 |
|  223 | 2019-01-08T00:00:00Z |        F |         5 |
|  223 | 2019-01-09T00:00:00Z |        F |         6 |
|  223 | 2019-01-19T00:00:00Z |        T |         1 |
|  223 | 2019-01-20T00:00:00Z |        T |         2 |
|  223 | 2019-01-21T00:00:00Z |        T |         3 |

【讨论】:

  • 当 USID 多于一个时,这不起作用。我也不能使用 Order by,因为我需要将其放入视图中,以便可以将数据推送到另一个工具。我能够解决日期问题,所以这不应该是一个问题。
  • 我将 USID 添加到 LAG 以获取多个 USID 值。
  • 只要从视图中选择后视图就可以简单地排序 -> SELECT * FROM MyView ORDER BY USID,Date
  • 在我的结果中,我没有得到正确的结果:USID Date Utilized RowNumber 155 9/28/2020 F 1 155 9/29/2020 F 2 155 9/30/2020 F 3 155 10 /1/2020 F 4 155 10/2/2020 F 1 155 10/5/2020 F 1 155 10/6/2020 F 2 155 10/7/2020 F 3 155 10/8/2020 F 1
  • 例如,如果您查看第 17 行的结果,它会由于某种原因再次重新启动为 1:223 2019-01-05 00:00:00.000 F 1。与第 23 行相同,倒数第二行
猜你喜欢
  • 1970-01-01
  • 2021-04-06
  • 2012-06-14
  • 2022-07-06
  • 1970-01-01
  • 2022-01-05
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多