如何仅对 SQL 中的一部分数据进行排名

How to rank only a subset of data in SQL

我已经为此苦苦挣扎了一段时间。我有一个像下面这样的 Oracle table。

ROW_NUM CATALOG CODE EVENT_DT
1 1 G 30-AUG-21
2 2 M 30-AUG-21
3 1 G_M 30-AUG-21
4 3 U 30-AUG-21
5 1 U 30-AUG-21
6 1 G 30-AUG-21
7 2 G_M 30-AUG-21

我想根据最早的 Event_DT 为目录 = 1 和代码 = G 或 G_M 引入排名。所有 EVENT_DT 都是一样的。我希望生成的 table 看起来像这样:

ROW_NUM CATALOG CODE EVENT_DT C_RANK
1 1 G 30-AUG-21 1
2 2 M 30-AUG-21
3 1 G_M 30-AUG-21 2
4 3 U 30-AUG-21
5 1 U 30-AUG-21
6 1 G 30-AUG-21 3
7 2 G_M 30-AUG-21

这是我试过的:

SELECT CATALOG, CODE, EVENT_DT,
CASE WHEN CODE NOT LIKE 'G%' THEN 0 ELSE ROW_NUMBER() OVER (PARITION BY CATALOG ORDER BY EVENT_DT ASC) END AS C_RANK
FROM TABLE
WHERE CATALOG = 1;

结果如下 table。第 6 行的排名应为 3。但是,目录 = 1 和代码 = U 的第 5 行也计入排名。我以为 case 语句会在第 5 行引入一个 0,看起来已经做到了,但也计入了排名。

ROW_NUM CATALOG CODE EVENT_DT C_RANK
1 1 G 30-AUG-21 1
2 2 M 30-AUG-21 0
3 1 G_M 30-AUG-21 2
4 3 U 30-AUG-21 0
5 1 U 30-AUG-21 0
6 1 G 30-AUG-21 4
7 2 G_M 30-AUG-21 0

您可以尝试将过滤器表达式 CODE LIKE 'G%' 添加到您的分区子句中。这将创建一个 true/false 值的子分区。此外,如果所有行都具有相同的日期,您的数据可能不会像您在示例中显示的那样自动排序。我在示例中添加了一个附加字段 ROW_NUM 以进行排序。根据您的实际数据集,您可以将其替换为合适的字段。

例如

SELECT
    t.*,
    CASE
        WHEN (CATALOG=1) AND (CODE LIKE 'G%') THEN ROW_NUMBER() OVER (
            PARTITION BY CATALOG,CASE WHEN (CODE LIKE 'G%') THEN 1 ELSE 0 END
            ORDER BY EVENT_DT,ROW_NUM
        )
    END as C_RANK
FROM
    my_table t
ORDER BY
    ROW_NUM;
row_num CATALOG code event_dt c_rank
1 1 G 2021-08-30T00:00:00.000Z 1
2 2 M 2021-08-30T00:00:00.000Z
3 1 G_M 2021-08-30T00:00:00.000Z 2
4 3 U 2021-08-30T00:00:00.000Z
5 1 U 2021-08-30T00:00:00.000Z
6 1 G 2021-08-30T00:00:00.000Z 3
7 2 G_M 2021-08-30T00:00:00.000Z

View working demo on DB Fiddle

让我知道这是否适合你。

如果你在 G 之后,你可以使用

SELECt "ROW_NUM", "CATALOG", "CODE", "EVENT_DT"
, CASE WHEN substr("CODE",1,1) = 'G' 
  THEN ROW_NUMBER() OVER (ORDER BY substr("CODE",1,1),"ROW_NUM") ELSE 0 END AS "c_rwn"
FROM tab1 ORDER BY "ROW_NUM"
ROW_NUM | CATALOG | CODE | EVENT_DT  | c_rwn
------: | ------: | :--- | :-------- | ----:
      1 |       1 | G    | 30-AUG-21 |     1
      2 |       2 | M    | 30-AUG-21 |     0
      3 |       1 | G_M  | 30-AUG-21 |     2
      4 |       3 | U    | 30-AUG-21 |     0
      5 |       1 | U    | 30-AUG-21 |     0
      6 |       1 | G    | 30-AUG-21 |     3
      7 |       2 | G_M  | 30-AUG-21 |     4

db<>fiddle here

因为你只想要目录 1

SELECt "ROW_NUM", "CATALOG", "CODE", "EVENT_DT"
, CASE WHEN substr("CODE",1,1) = 'G' AND "CATALOG" = 1 
  THEN ROW_NUMBER() OVER (ORDER BY substr("CODE",1,1),"ROW_NUM") ELSE 0 END AS "c_rwn"
FROM tab1 ORDER BY "ROW_NUM"
ROW_NUM | CATALOG | CODE | EVENT_DT  | c_rwn
------: | ------: | :--- | :-------- | ----:
      1 |       1 | G    | 30-AUG-21 |     1
      2 |       2 | M    | 30-AUG-21 |     0
      3 |       1 | G_M  | 30-AUG-21 |     2
      4 |       3 | U    | 30-AUG-21 |     0
      5 |       1 | U    | 30-AUG-21 |     0
      6 |       1 | G    | 30-AUG-21 |     3
      7 |       2 | G_M  | 30-AUG-21 |     0

db<>fiddle here