2

我有一张表格可以跟踪客户资料的变化。这是一个简化版本

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');

该数据由第三方维护。我的最终目标是在给定的时间跨度内获得每种帐户类型和月份的客户总和,但现在,我想从更简单的开始——显示记录更改的每个月/客户组合的最新帐户类型:

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

在这里,客户 100 在 3 月份进行了三处更改;我们显示“Premium”,因为它的最新日期在 3 月内。

获取所有行的查询是这样的:

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

是否可以使用聚合函数过滤掉不需要的行?使用分析函数是否更有意义?

(而且,在任何一种情况下,适当的功能是什么?)

编辑:有人问我不需要的行的例子。3 月份的客户 100 有 3 行:

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

不需要的行是'Free'并且'Standard'因为它们不是本月最新的。

4

3 回答 3

2
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

于 2013-05-08T09:07:48.297 回答
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

于 2013-05-08T09:20:18.190 回答
1
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

输出

╔══════╦═══════╦═════════════╦══════════════╗
║ YEAR ║ MONTH ║ CUSTOMER_ID ║ ACCOUNT_TYPE ║
╠══════╬═══════╬═════════════╬══════════════╣
║ 2013 ║     1 ║         200 ║ Premium      ║
║ 2013 ║     2 ║         300 ║ Free         ║
║ 2013 ║     3 ║         100 ║ Premium      ║
║ 2013 ║     3 ║         200 ║ Standard     ║
╚══════╩═══════╩═════════════╩══════════════╝
于 2013-05-08T09:08:30.843 回答