2016-06-26 5 views
0

У меня есть таблица с именем 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 должен быть идентифицирован как разрывной data.In моего кода, который я в настоящее время использовать следующий запрос для выявления разрывных данных. 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); 

ответ

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; 

Одна из ваших проблем является то, что ваш непрерывный желаемый результат также включает в себя перекрывающиеся диапазоны дат в вашем примере набора данных. Пример A111326 Начинается с 3/2/2016, но заканчивается строка до 3/5/2015, что означает, что она перекрывается на 3 дня. Настройка

+0

Спасибо много для решения. Это действительно сработало. У меня есть данные, которые смежны и перекрываются. Но это работает. – manj

+0

Да, я изменил запрос, когда заметил, что перекрытие позволяет считать его непрерывным. Если в будущем вы никогда не захотите включать перекрывающиеся изменения> = Start_Dt - 1 to = Start_Dt - 1. Рад, что это сработало, если вы могли бы принять ответ, который будет оценен (http://meta.stackexchange.com/questions/5234/how-do-accepting-an-answer-work) – Matt

+0

Попробуйте строки ''E', DATE '2016-01-01', DATE '2016-01-02''; ''E', DATE '2016-01-05', DATE '2016-01-06''; и ''E', DATE '2016-01-03', DATE '2016-01-07'' он выводит 'discontiguous', когда он фактически' смежный'. – MT0

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; 
+0

Мне нравится этот шаблон, используя общее количество на дату и уровень. Я согласен, что это более полное доказательство и обрабатывает вопрос о том, когда третья строка смежна, а вторая - нет. Спасибо за ответ и заметьте, я, вероятно, воспользуюсь этим еще некоторое время. – Matt

+0

@Matt - его адаптированный из моего ответа на [этот вопрос] (http://stackoverflow.com/a/35521818/1509264) (который извлекает даты начала и окончания перекрывающихся диапазонов с использованием первых двух частей вышеуказанного метода и 'LAG (...) IGNORE NULLS'). – MT0

Смежные вопросы