SQL first date for the first occurrence of a value

我与影子孤独终老i 提交于 2021-01-29 08:28:19

问题


I have a table with clients and the history of their rating (low, medium, high) which gets assessed quarterly.

Example table:

client_ID  rating  eff_from
111  high  30.09.2018
111  high  30.06.2018
111  medium  31.03.2018
111  high  31.12.2017
111  high  30.09.2017
111  low  30.06.2017
222  medium  30.09.2018
222  high  30.06.2018
222  high  31.03.2018
222  low  31.12.2017
222  low  30.09.2017
222  medium  30.06.2017

I would like to get the minimum eff_from date for the latest rating. From the table above, that would be 30.06.2018 for client 111 and 30.09.2018 for client 222.

The trick is that the rating can change for example from high to medium and back to high, so grouping by client and rating and taking the minimum eff_from date doesn't work - it would result in 30.09.2017 for client 111.

The environment is a DB2 database and the eff_from field is formatted as date.

Any ideas?


回答1:


Here's one way to tackle your problem:

CREATE TABLE #T (ClientID INT, RATING VARCHAR (20), eff_From DATE)

INSERT INTO #T VALUES
(111, 'high',  '20180930'  ), 
(111, 'high',  '20180630'  ) ,
(111, 'medium', '20180331' ) ,
(111, 'high',  '20171231'  ) ,
(111, 'high', '20170930'      ) ,
(111, 'low', '20170630'   ); 

WITH CTE AS 
(
    SELECT *, ROW_NUMBER() OVER (PARTITION BY ClientID ORDER BY  eff_From) AS RowNumb
    FROM #T
)

SELECT C.*, 
      C2.RATING AS C2Rating,
      C2.eff_From AS C2EffFrom,
      CASE WHEN C.RATING <> C2.RATING THEN 1 ELSE 0 END AS RatingChanged 
INTO #T2
FROM CTE AS C
LEFT JOIN CTE AS C2 ON C.RowNumb = C2.RowNumb - 1

SELECT ClientID, MAX (C2EffFrom) AS MaxEffFrom
FROM #T2
WHERE RatingChanged = 1
GROUP BY ClientID



回答2:


That depends on the SQL-dialect you are using. In Microsofts Transact-SQL I know that there is the structure ROWNUMBER, that helps in these situations. maybe there is something similar in your's, too

Example (T-SQL):

SELECT eff_from FROM
(
    SELECT
        *,
        ROW_NUMBER() OVER(PARTITION BY client_ID ORDER BY eff_from ASC) AS RN
    FROM
        EXAMPLE_TABLE
) TABLE_WITH_RN
WHERE
    RN = 1



回答3:


You need conditional ordering with row_number() :

select t.*,
       row_number() over (partition by client_id
                          order by (case when rating = 'low' 
                                         then 1 
                                         else 2
                                    end), eff_from
                         ) as seq
from table t;

Then next to use that in subquery & filter the sequence :

select *
from ( < query > 
     ) t
where seq = 1;

However, honestly i Don't know conditional ordering would work or not ?, but this would give a idea how to do in other way if conditional ordering would not work.

EDIT : You can also use window function if above not work :

 select t.*,
        min(case when rating = 'low' then eff_from end) over (partition by client_id)
 from table t;



回答4:


Try this:

select client_ID, min(eff_from) eff_from
from (
select client_ID, eff_from
, sum(
  case 
  when rating=coalesce(lag(rating) over(partition by client_ID order by eff_from desc), rating) then 0
  else 1
  end
  ) over(partition by client_ID order by eff_from desc) s_
from tab
)
where s_=0
group by client_ID;


来源:https://stackoverflow.com/questions/53708122/sql-first-date-for-the-first-occurrence-of-a-value

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