如何仅对 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
我已经为此苦苦挣扎了一段时间。我有一个像下面这样的 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