Row with latest value by customer and month [duplicate]

五迷三道 提交于 2021-01-04 04:20:39

问题


I have a table that keeps track of changes in customer profiles. Here's a simplified version:

CREATE TABLE HISTORY (
    CUSTOMER_ID NUMBER(9,0), 
    DATE_CHANGED DATE, 
    ACCOUNT_TYPE VARCHAR2(20),

    CONSTRAINT HISTORY_PK PRIMARY KEY (CUSTOMER_ID, DATE_CHANGED)
);

INSERT INTO HISTORY (CUSTOMER_ID, DATE_CHANGED, ACCOUNT_TYPE) VALUES (200, TO_DATE('05/01/2013 00:00:00','DD/MM/RRRR HH24:MI:SS'), 'Premium');
INSERT INTO HISTORY (CUSTOMER_ID, DATE_CHANGED, ACCOUNT_TYPE) VALUES (300, TO_DATE('17/02/2013 00:00:00','DD/MM/RRRR HH24:MI:SS'), 'Free');
INSERT INTO HISTORY (CUSTOMER_ID, DATE_CHANGED, ACCOUNT_TYPE) VALUES (100, TO_DATE('05/03/2013 00:00:00','DD/MM/RRRR HH24:MI:SS'), 'Free');
INSERT INTO HISTORY (CUSTOMER_ID, DATE_CHANGED, ACCOUNT_TYPE) VALUES (100, TO_DATE('12/03/2013 00:00:00','DD/MM/RRRR HH24:MI:SS'), 'Standard');
INSERT INTO HISTORY (CUSTOMER_ID, DATE_CHANGED, ACCOUNT_TYPE) VALUES (200, TO_DATE('22/03/2013 00:00:00','DD/MM/RRRR HH24:MI:SS'), 'Standard');
INSERT INTO HISTORY (CUSTOMER_ID, DATE_CHANGED, ACCOUNT_TYPE) VALUES (100, TO_DATE('29/03/2013 00:00:00','DD/MM/RRRR HH24:MI:SS'), 'Premium');

That data is maintained by a third-party. My ultimate goal is to obtain a sum of customers per account type and month for a given timespan but, by now, I'd like to start with something simpler—display the latest account type for each month/customer combination where there are changes recorded:

YEAR MONTH CUSTOMER_ID ACCOUNT_TYPE
==== ===== =========== ============
2013     1         200 Premium
2013     2         300 Free
2013     3         100 Premium
2013     3         200 Standard

Here, customer 100 has made three changes on March; we display "Premium" because it has the latest date within March.

The query to obtain all rows would be this:

SELECT EXTRACT(YEAR FROM DATE_CHANGED) AS YEAR,
EXTRACT(MONTH FROM DATE_CHANGED) AS MONTH,
CUSTOMER_ID, ACCOUNT_TYPE
FROM HISTORY
ORDER BY YEAR, MONTH, CUSTOMER_ID, DATE_CHANGED

Is it possible to filter out unwanted rows using aggregate functions? Does it make more sense to use analytic functions?

(And, in either case, what would be the adequate function?)

Edit: I've been asked for an example of unwanted rows. There're 3 rows for customer 100 on March:

'05/03/2013 00:00:00', 'Free'
'12/03/2013 00:00:00', 'Standard'
'29/03/2013 00:00:00', 'Premium'

Unwanted rows are 'Free' and 'Standard' because they aren't the latest in the month.


回答1:


SELECT YEAR
      ,MONTH
      ,customer_id
      ,max(ACCOUNT_TYPE) keep(dense_rank FIRST ORDER BY date_changed DESC) LAST_ACC
 FROM (
  SELECT EXTRACT(YEAR FROM DATE_CHANGED) AS YEAR,
         EXTRACT(MONTH FROM DATE_CHANGED) AS MONTH,
         CUSTOMER_ID,
         date_changed,
         account_type
   FROM HISTORY
  )
GROUP BY YEAR, MONTH, customer_id
ORDER BY YEAR, MONTH, CUSTOMER_ID


| YEAR | MONTH | CUSTOMER_ID | LAST_ACC |
-----------------------------------------
| 2013 |     1 |         200 |  Premium |
| 2013 |     2 |         300 |     Free |
| 2013 |     3 |         100 |  Premium |
| 2013 |     3 |         200 | Standard |

http://sqlfiddle.com/#!4/e493a/15




回答2:


SELECT  DISTINCT
CUSTOMER_ID,
EXTRACT(YEAR FROM DATE_CHANGED) AS YEAR,
EXTRACT(MONTH FROM DATE_CHANGED) AS MONTH,
LAST_VALUE(ACCOUNT_TYPE) 
OVER(PARTITION BY CUSTOMER_ID,TO_CHAR(DATE_CHANGED,'YYYY-MM') ORDER BY DATE_CHANGED ROWS BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING) AS ACCOUNT_TYPE
FROM HISTORY



CUSTOMER_ID YEAR    MONTH   ACCOUNT_TYPE
200         2013    1   Premium
300         2013    2   Free
100         2013    3   Premium
200         2013    3   Standard

http://www.sqlfiddle.com/#!4/fab60/13




回答3:


SELECT YEAR, MONTH, CUSTOMER_ID, ACCOUNT_TYPE
FROM 
(
SELECT EXTRACT(YEAR FROM DATE_CHANGED) AS YEAR,
       EXTRACT(MONTH FROM DATE_CHANGED) AS MONTH,
       CUSTOMER_ID, 
       ACCOUNT_TYPE,
       ROW_NUMBER() OVER (PARTITION BY CUSTOMER_ID, 
                                       EXTRACT(YEAR FROM DATE_CHANGED),
                                       EXTRACT(MONTH FROM DATE_CHANGED)
                          ORDER BY EXTRACT(YEAR FROM DATE_CHANGED) DESC,
                                   EXTRACT(MONTH FROM DATE_CHANGED) DESC,
                                   DATE_CHANGED DESC) RN
FROM   HISTORY
)
WHERE RN = 1
ORDER BY YEAR, MONTH, CUSTOMER_ID
  • SQLFiddle Demo

OUTPUT

╔══════╦═══════╦═════════════╦══════════════╗
║ YEAR ║ MONTH ║ CUSTOMER_ID ║ ACCOUNT_TYPE ║
╠══════╬═══════╬═════════════╬══════════════╣
║ 2013 ║     1 ║         200 ║ Premium      ║
║ 2013 ║     2 ║         300 ║ Free         ║
║ 2013 ║     3 ║         100 ║ Premium      ║
║ 2013 ║     3 ║         200 ║ Standard     ║
╚══════╩═══════╩═════════════╩══════════════╝


来源:https://stackoverflow.com/questions/16436516/row-with-latest-value-by-customer-and-month

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