Oracle SQL conditional ranking

断了今生、忘了曾经 提交于 2021-01-28 09:51:14

问题


In my query, I am doing multiple types of ranking and for one of ranking types, I want to rank the row only if certain column is not null. Else I don't want ranking to happen.

For example here's a sample table:

+------+------------+------------+--------+--------+
| col1 |    col2    |    col3    | rank 1 | rank 2 |
+------+------------+------------+--------+--------+
| a    | 2018-01-20 | 2018-03-04 |      2 | 2      |
| a    | 2018-01-24 | 2018-04-04 |      1 | 1      |
| b    | 2018-01-02 | 2018-05-03 |      1 | 1      |
| c    | 2017-01-02 | 2017-05-08 |      3 | 2      |
| d    | 2016-05-24 | null       |      1 | null   |
| c    | 2018-02-05 | 2018-05-03 |      2 | 1      |
| c    | 2018-07-28 | null       |      1 | null   |
+------+------------+------------+--------+--------+

rank1 is calculated alright based on partition by col1 order by col2 desc rank 2 should be calculated the same way, but only when when col3 is null, else it should be null.

How can I achieve both ranks in a single query? I tried to use case statement for rank2, but it skips the ranking when col3 is null,


回答1:


If I understand corrcly, you can try to use CASE WHEN with sum window function

CASE WHEN check col3 isn't null do accumulate else display NULL

CREATE TABLE T(
  col1 VARCHAR(5),
  col2 DATE,
  col3 DATE
);

INSERT INTO T VALUES ( 'a' , to_date('2018-01-20','YYYY-MM-DD') , to_date('2018-03-04','YYYY-MM-DD'));  
INSERT INTO T VALUES ( 'a' , to_date('2018-01-24','YYYY-MM-DD') , to_date('2018-04-04','YYYY-MM-DD'));  
INSERT INTO T VALUES ( 'b' , to_date('2018-01-02','YYYY-MM-DD') , to_date('2018-05-03','YYYY-MM-DD'));  
INSERT INTO T VALUES ( 'c' , to_date('2017-01-02','YYYY-MM-DD') , to_date('2017-05-08','YYYY-MM-DD'));  
INSERT INTO T VALUES ( 'd' , TO_DATE('2016-05-24','YYYY-MM-DD') , null);  
INSERT INTO T VALUES ( 'c' , TO_DATE('2018-02-05','YYYY-MM-DD') , to_date('2018-05-03','YYYY-MM-DD'));  
INSERT INTO T VALUES ( 'c' , TO_DATE('2018-07-28','YYYY-MM-DD') , null);  

Query 1:

select t1.*,
    rank() OVER(partition by col1 order by col2 desc) rank1,
    (CASE WHEN COL3 IS NOT NULL THEN
       SUM(CASE WHEN COL3 IS NOT NULL THEN 1 ELSE 0 END) OVER(partition by col1 order by col2 desc)
    ELSE
       NULL
    END) rank2
FROM T t1

Results:

| COL1 |                 COL2 |                 COL3 | RANK1 |  RANK2 |
|------|----------------------|----------------------|-------|--------|
|    a | 2018-01-24T00:00:00Z | 2018-04-04T00:00:00Z |     1 |      1 |
|    a | 2018-01-20T00:00:00Z | 2018-03-04T00:00:00Z |     2 |      2 |
|    b | 2018-01-02T00:00:00Z | 2018-05-03T00:00:00Z |     1 |      1 |
|    c | 2018-07-28T00:00:00Z |               (null) |     1 | (null) |
|    c | 2018-02-05T00:00:00Z | 2018-05-03T00:00:00Z |     2 |      1 |
|    c | 2017-01-02T00:00:00Z | 2017-05-08T00:00:00Z |     3 |      2 |
|    d | 2016-05-24T00:00:00Z |               (null) |     1 | (null) |



回答2:


I think you might want:

select count(col3) over (partition by col1 order by col2 desc)

Note that this is equivalent to row_number() rather than rank(). For your data these are equivalent.



来源:https://stackoverflow.com/questions/51895196/oracle-sql-conditional-ranking

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!