确定连续和不连续的日期范围

时间:2016-06-26 16:46:56

标签: sql oracle

我有一张名为x的表。数据如下。

Acccount_num    start_dt    end_dt
A111326      02/01/2016    02/11/2016
A111326      02/12/2016    03/05/2016
A111326      03/02/2016   03/16/2016
A111331      02/28/2016   02/29/2016
A111331      02/29/2016   03/29/2016
A999999      08/25/2015   08/25/2015
A999999      12/19/2015   12/22/2015
A222222      11/06/2015   11/10/2015
A222222      05/16/2016   05/17/2016

A111326和A111331都应标识为连续数据和A999999和
应将A222222标识为不连续数据。在我的代码中,我目前使用以下查询来识别不连续数据。 A111326也被错误地识别为不连续数据。请帮助修改以下代码,以便A111326不被识别为不连续数据。请提前感谢您的帮助。

(SELECT account_num
                FROM (SELECT account_num,
                             (MAX (
                                 END_DT)
                              OVER (PARTITION BY account_num
                                    ORDER BY START_DT))
                                START_DT,
                             (LEAD (
                                 START_DT)
                              OVER (PARTITION BY account_num
                                    ORDER BY START_DT))
                                END_DT
                        FROM x
                         WHERE (START_DT + 1) <=
                                (END_DT - 1))
               WHERE START_DT < END_DT);

2 个答案:

答案 0 :(得分:2)

Oracle安装程序

CREATE TABLE accounts ( Account_num, start_dt, end_dt ) AS
SELECT 'A', DATE '2016-02-01', DATE '2016-02-11' FROM DUAL UNION ALL
SELECT 'A', DATE '2016-02-12', DATE '2016-03-05' FROM DUAL UNION ALL
SELECT 'A', DATE '2016-03-02', DATE '2016-03-16' FROM DUAL UNION ALL
SELECT 'B', DATE '2016-02-28', DATE '2016-02-29' FROM DUAL UNION ALL
SELECT 'B', DATE '2016-02-29', DATE '2016-03-29' FROM DUAL UNION ALL
SELECT 'C', DATE '2015-08-25', DATE '2015-08-25' FROM DUAL UNION ALL
SELECT 'C', DATE '2015-12-19', DATE '2015-12-22' FROM DUAL UNION ALL
SELECT 'D', DATE '2015-11-06', DATE '2015-11-10' FROM DUAL UNION ALL
SELECT 'D', DATE '2016-05-16', DATE '2016-05-17' FROM DUAL UNION ALL
SELECT 'E', DATE '2016-01-01', DATE '2016-01-02' FROM DUAL UNION ALL
SELECT 'E', DATE '2016-01-05', DATE '2016-01-06' FROM DUAL UNION ALL
SELECT 'E', DATE '2016-01-03', DATE '2016-01-07' FROM DUAL;

<强>查询

WITH times ( account_num, dt, lvl ) AS (
  SELECT Account_num, start_dt - 1,  1 FROM accounts
UNION ALL
  SELECT Account_num, end_dt,       -1 FROM accounts
)
, totals ( account_num, dt, total ) AS (
  SELECT account_num,
         dt,
         SUM( lvl ) OVER ( PARTITION BY Account_num ORDER BY dt, lvl DESC )
  FROM   times
)
SELECT Account_num,
       CASE WHEN COUNT( CASE total WHEN 0 THEN 1 END ) > 1
            THEN 'N'
            ELSE 'Y'
            END AS is_contiguous
FROM   totals
GROUP BY Account_Num
ORDER BY Account_Num;

<强>输出

ACCOUNT_NUM IS_CONTIGUOUS
----------- -------------
A           Y
B           Y
C           N
D           N
E           Y

替代查询

(仅使用UNPIVOT而非UNION ALL的方法完全相同。)

SELECT Account_num,
       CASE WHEN COUNT( CASE total WHEN 0 THEN 1 END ) > 1
            THEN 'N'
            ELSE 'Y'
            END AS is_contiguous
FROM   (
  SELECT Account_num,
         SUM( lvl ) OVER ( PARTITION BY Account_Num
                           ORDER BY CASE lvl WHEN 1 THEN dt - 1 ELSE dt END,
                                    lvl DESC
                         ) AS total
  FROM   accounts
  UNPIVOT ( dt FOR lvl IN ( start_dt AS 1, end_dt AS -1 ) )
)
GROUP BY Account_Num
ORDER BY Account_Num;

答案 1 :(得分:0)

WITH cte AS (
    SELECT
       AccountNumber
       ,CASE
          WHEN
             LAG(End_Dt) OVER (PARTITION BY AccountNumber ORDER BY End_Dt) IS NULL THEN 0
          WHEN
             LAG(End_Dt) OVER (PARTITION BY AccountNumber ORDER BY End_Dt) >= Start_Dt - 1 THEN 0
          ELSE 1
       END as discontiguous 
    FROM
       #Table
)

SELECT
    AccountNumber
    ,CASE WHEN SUM(discontiguous) > 0 THEN 'discontiguous' ELSE 'contiguous' END
FROM
    cte
GROUP BY
    AccountNumber;

您的一个问题是您的连续所需结果还包括示例数据集中的重叠日期范围。示例A1113263/2/2016开始,但在3/5/2015之前结束行,意味着它重叠了3天。

相关问题