ROW_NUMBER 在具有重复排序依据值的 PARTITION 上生成

ROW_NUMBER to generate on PARTITION with duplicate Order By value

我正在访问 SQL 服务器中的视图,该视图从应用程序中存储如下

SELECT *
FROM
    (
        VALUES 
            (1, 'Open', { ts '2020-01-10 23:56:12' }), 
            (1, 'Started', { ts '2020-01-10 23:56:12' }), 
            (1, 'Hold', { ts '2020-01-10 23:56:12' }), 
            (1, 'Sent', { ts '2020-01-11 15:33:22' }), 
            (1, 'Complete', { ts '2020-01-11 15:36:22' }), 
            (1, 'Closed', { ts '2020-01-13 16:43:33' }), 
            (2, 'Open', { ts '2020-02-22 06:43:33' }), 
            (2, 'Started', { ts '2020-02-22 06:43:33' }), 
            (2, 'Clarify', { ts '2020-03-23 08:33:53' }), 
            (2, 'Closed', { ts '2020-03-24 08:33:53' })
        ) t (WO, WO_Status, WO_Status_Date)

这会生成以下内容

| WO | WO_Status | WO_Status_Date          |
+----+-----------+-------------------------+
| 1  | Open      | 2020-01-10 23:56:12.000 |
| 1  | Started   | 2020-01-10 23:56:12.000 |
| 1  | Hold      | 2020-01-10 23:56:12.000 |
| 1  | Sent      | 2020-01-11 15:33:22.000 |
| 1  | Complete  | 2020-01-11 15:36:22.000 |
| 1  | Closed    | 2020-01-13 16:43:33.000 |
| 2  | Open      | 2020-02-22 06:43:33.000 |
| 2  | Started   | 2020-02-22 06:43:33.000 |
| 2  | Clarify   | 2020-03-23 08:33:53.000 |
| 2  | Closed    | 2020-03-24 08:33:53.000 |

我只想根据行的固有顺序创建一个行号/WO。

所以我想要的输出是

| WO | WO_Status | WO_Status_Date          | Order |
+----+-----------+-------------------------+-------+
| 1  | Open      | 2020-01-10 23:56:12.000 | 1     |
| 1  | Started   | 2020-01-10 23:56:12.000 | 2     |
| 1  | Hold      | 2020-01-10 23:56:12.000 | 3     |
| 1  | Sent      | 2020-01-11 15:33:22.000 | 4     |
| 1  | Complete  | 2020-01-11 15:36:22.000 | 5     |
| 1  | Closed    | 2020-01-13 16:43:33.000 | 6     |
| 2  | Open      | 2020-02-22 06:43:33.000 | 1     |
| 2  | Started   | 2020-02-22 06:43:33.000 | 2     |
| 2  | Clarify   | 2020-03-23 08:33:53.000 | 3     |
| 2  | Closed    | 2020-03-24 08:33:53.000 | 4     |

为此,我尝试了以下方法

SELECT
    a.*,
    ROW_NUMBER() OVER (PARTITION BY (a.[WO]) ORDER BY a.[WO_Status_Date] ASC) AS [Natural Order]
FROM
    (SELECT *
     FROM
         (VALUES 
            (1, 'Open', { ts '2020-01-10 23:56:12' }), 
            (1, 'Started', { ts '2020-01-10 23:56:12' }), 
            (1, 'Hold', { ts '2020-01-10 23:56:12' }), 
            (1, 'Sent', { ts '2020-01-11 15:33:22' }), 
            (1, 'Complete', { ts '2020-01-11 15:36:22' }), 
            (1, 'Closed', { ts '2020-01-13 16:43:33' }), 
            (2, 'Open', { ts '2020-02-22 06:43:33' }), 
            (2, 'Started', { ts '2020-02-22 06:43:33' }), 
            (2, 'Clarify', { ts '2020-03-23 08:33:53' }), 
            (2, 'Closed', { ts '2020-03-24 08:33:53' })
        ) t (WO, WO_Status, WO_Status_Date)
    ) a

生成此结果:

| WO | WO_Status | WO_Status_Date          | Natural Order |
+----+-----------+-------------------------+---------------+
| 1  | Started   | 2020-01-10 23:56:12.000 | 1             |
| 1  | Hold      | 2020-01-10 23:56:12.000 | 2             |
| 1  | Open      | 2020-01-10 23:56:12.000 | 3             |
| 1  | Sent      | 2020-01-11 15:33:22.000 | 4             |
| 1  | Complete  | 2020-01-11 15:36:22.000 | 5             |
| 1  | Closed    | 2020-01-13 16:43:33.000 | 6             |
| 2  | Started   | 2020-02-22 06:43:33.000 | 1             |
| 2  | Open      | 2020-02-22 06:43:33.000 | 2             |
| 2  | Clarify   | 2020-03-23 08:33:53.000 | 3             |
| 2  | Closed    | 2020-03-24 08:33:53.000 | 4             |

ORDER BY 正在覆盖具有重复值的行的固有顺序。有没有办法通过这个得到想要的结果。

首先,您应该知道,就关系数据库而言,没有所谓的“自然顺序”。这是一种误解。
事实上,这是一个非常普遍的误解,我已经写了一篇关于它的文章 blog post 因为尽管它在这么多网站上被这么多专业人士反驳了这么多次,但仍然有太多的开发人员成为这种误解的受害者.

现在,话虽如此,我假设不同的状态应该按照业务逻辑顺序规则进行排序 - 这可以使用 table 来完成,状态包含一个列来排序,或者通过在 order by 子句中使用 case 表达式。

这个 SQL 语句会给你想要的结果(假设我已经正确地得到了不同状态的顺序):

SELECT  WO, 
        WO_Status, 
        WO_Status_Date,
        ROW_NUMBER() OVER(PARTITION BY WO ORDER BY 
            WO_Status_Date, 
            CASE WO_Status 
                WHEN 'Open' Then 1
                WHEN 'Started' Then 2
                WHEN 'Hold' Then 3
                WHEN 'Clarify' Then 4
                WHEN 'Sent' Then 5
                WHEN 'Complete' Then 6
                WHEN 'Closed' Then 7
            END) As [Natural Order]
FROM
(
    VALUES 
        (1, 'Open', { ts '2020-01-10 23:56:12' }), 
        (1, 'Started', { ts '2020-01-10 23:56:12' }), 
        (1, 'Hold', { ts '2020-01-10 23:56:12' }), 
        (1, 'Sent', { ts '2020-01-11 15:33:22' }), 
        (1, 'Complete', { ts '2020-01-11 15:36:22' }), 
        (1, 'Closed', { ts '2020-01-13 16:43:33' }), 
        (2, 'Open', { ts '2020-02-22 06:43:33' }), 
        (2, 'Started', { ts '2020-02-22 06:43:33' }), 
        (2, 'Clarify', { ts '2020-03-23 08:33:53' }), 
        (2, 'Closed', { ts '2020-03-24 08:33:53' })
    ) t (WO, WO_Status, WO_Status_Date)