Search code examples
sqloracle-databasesql-order-byrownum

Select Only One Row, by Value Field, Ordering


This Question extends from Oracle SQL Where Conditions weight but, is more general (without product restriction, but give one by product value).

I have a table

DROP TABLE mytable;
CREATE TABLE mytable 
(
    product_code VARCHAR2(20 BYTE) NOT NULL ENABLE, 
    priority NUMBER NOT NULL ENABLE, 
    date_act DATE, 
    date_dis DATE
);

Populate the table

INSERT INTO mytable (product_code, priority, date_act, date_dis) VALUES ('bla', '0', TO_DATE('2019-01-01', 'YYYY-MM-DD'), TO_DATE('2019-01-31', 'YYYY-MM-DD'));
INSERT INTO mytable (product_code, priority, date_act, date_dis) VALUES ('bla', '1', TO_DATE('2019-02-01', 'YYYY-MM-DD'), TO_DATE('2019-02-28', 'YYYY-MM-DD'));
INSERT INTO mytable (product_code, priority, date_act) VALUES ('bla', '2', TO_DATE('2019-01-01', 'YYYY-MM-DD'));
INSERT INTO mytable (product_code, priority, date_act) VALUES ('bla', '3', TO_DATE('2019-02-01', 'YYYY-MM-DD'));
INSERT INTO mytable (product_code, priority, date_dis) VALUES ('bla', '4', TO_DATE('2019-01-31', 'YYYY-MM-DD'));
INSERT INTO mytable (product_code, priority, date_dis) VALUES ('bla', '5', TO_DATE('2019-02-28', 'YYYY-MM-DD'));
INSERT INTO mytable (product_code, priority) VALUES ('bla', '6');
INSERT INTO mytable (product_code, priority) VALUES ('bla', '7');

INSERT INTO mytable (product_code, priority, date_act, date_dis) VALUES ('foo', '0', TO_DATE('2019-01-01', 'YYYY-MM-DD'), TO_DATE('2019-01-31', 'YYYY-MM-DD'));
INSERT INTO mytable (product_code, priority, date_act) VALUES ('foo', '1', TO_DATE('2019-02-01', 'YYYY-MM-DD'));
INSERT INTO mytable (product_code, priority, date_dis) VALUES ('foo', '2', TO_DATE('2019-01-31', 'YYYY-MM-DD'));
INSERT INTO mytable (product_code, priority) VALUES ('foo', '3');


INSERT INTO mytable (product_code, priority, date_act, date_dis) VALUES ('tmp', '0', TO_DATE('2019-01-01', 'YYYY-MM-DD'), TO_DATE('2019-01-31', 'YYYY-MM-DD'));
INSERT INTO mytable (product_code, priority, date_act) VALUES ('tmp', '1', TO_DATE('2019-01-01', 'YYYY-MM-DD'));
INSERT INTO mytable (product_code, priority, date_dis) VALUES ('tmp', '2', TO_DATE('2019-02-28', 'YYYY-MM-DD'));
INSERT INTO mytable (product_code, priority) VALUES ('tmp', '3');

The content

SELECT * FROM mytable;

And Output

PRODUCT_CODE           PRIORITY DATE_ACT  DATE_DIS 
-------------------- ---------- --------- ---------
bla                           0 01-JAN-19 31-JAN-19
bla                           1 01-FEB-19 28-FEB-19
bla                           2 01-JAN-19          
bla                           3 01-FEB-19          
bla                           4           31-JAN-19
bla                           5           28-FEB-19
bla                           6                    
bla                           7                    
foo                           0 01-JAN-19 31-JAN-19
foo                           1 01-FEB-19          
foo                           2           31-JAN-19
foo                           3                    
tmp                           0 01-JAN-19 31-JAN-19
tmp                           1 01-JAN-19          
tmp                           2           28-FEB-19
tmp                           3                    

Condition definitions

  • condition_weight 4: When the row has date_act and date_dis defined.
  • condition_weight 3: When the row has date_dis defined but date_act not.
  • condition_weight 2: When the row has date_act defined but date_dis not.
  • condition_weight 1: When the row has date_act and date_dis not defined.

If condition_weight 4 is true the left (3, 2 and 1) will be ignored.

If condition_weight 4 is false and condition_weight 3 is true , condition_weight 2 and condition_weight 1 will be ignored.

If condition_weight 4 and 3 are false and condition_weight 2 is true condition_weight 1 will be ignored.

If condition_weight 4, 3 and 2 are false only condition_weight 1 will be evaluated.

THE QUESTION: How obtain only one row by each product_code with its priority highest, with input parameter date_submit with condition weight definitions?

EXAMPLE of OUTPUT Required NOTE: The below table results are created manually (I need similar results, but I don't have the query).

DATE_SUBMIT :='2019/01/15'

CONDITION_WEIGHT       PRIO PRODUCT_CODE           PRIORITY DATE_ACT  DATE_DIS  :DATE_SUBMIT                                                                                                                    
---------------- ---------- -------------------- ---------- --------- --------- --------------------------------------------------------------------------------------------------------------------------------
               4          0 bla                           0 01-JAN-19 31-JAN-19 2019/01/15                                                                                                                      
               4          0 foo                           0 01-JAN-19 31-JAN-19 2019/01/15                                                                                                                      
               4          0 tmp                           0 01-JAN-19 31-JAN-19 2019/01/15                                                                                                                      

DATE_SUBMIT :='2019/02/15'

CONDITION_WEIGHT       PRIO PRODUCT_CODE           PRIORITY DATE_ACT  DATE_DIS  :DATE_SUBMIT                                                                                                                    
---------------- ---------- -------------------- ---------- --------- --------- --------------------------------------------------------------------------------------------------------------------------------
               4          1 bla                           1 01-FEB-19 28-FEB-19 2019/02/15                                                                                                                      
               2          1 foo                           1 01-FEB-19           2019/02/15                                                                                                                      
               3          2 tmp                           2           28-FEB-19 2019/02/15                                                                                                                      

DATE_SUBMIT :='2018/12/31'

CONDITION_WEIGHT       PRIO PRODUCT_CODE           PRIORITY DATE_ACT  DATE_DIS  :DATE_SUBMIT                                                                                                                    
---------------- ---------- -------------------- ---------- --------- --------- --------------------------------------------------------------------------------------------------------------------------------
               3          5 bla                           5           28-FEB-19 2018/12/31                                                                                                                      
               3          2 foo                           2           31-JAN-19 2018/12/31                                                                                                                      
               3          2 tmp                           2           28-FEB-19 2018/12/31                                                                                                                      

DATE_SUBMIT :='2019/12/31'

CONDITION_WEIGHT       PRIO PRODUCT_CODE           PRIORITY DATE_ACT  DATE_DIS  :DATE_SUBMIT                                                                                                                    
---------------- ---------- -------------------- ---------- --------- --------- --------------------------------------------------------------------------------------------------------------------------------
               2          3 bla                           3 01-FEB-19           2019/12/31                                                                                                                      
               2          1 foo                           1 01-FEB-19           2019/12/31                                                                                                                      
               2          1 tmp                           1 01-JAN-19           2019/12/31                                                                                                                      

Check the answer https://stackoverflow.com/a/59779653/1410223 result, but if is it possible more simpler Query.

EDIT Only priority with highest priority must be .


Solution

  • Assign condition weights using case when. Then take best row for each product, use rank():

    with 
      d as (select date '2019-02-15' date_submit from dual),
      t as (
        select m.*, case 
                    when date_act is not null and date_dis is not null then 4 
                    when date_act is null and date_dis is not null then 3
                    when date_act is not null and date_dis is null then 2
                    else 1 end condition
          from mytable m)
    select product_code, priority, date_act, date_dis, condition, date_submit 
      from (
        select t.*, d.*, 
               rank() over ( partition by product_code order by condition desc ) rnk
          from t join d 
            on date_submit between nvl(date_act, date_submit) and nvl(date_dis, date_submit))
      where rnk = 1