1
votes

Comment trouver les dates manquantes dans les séries de données mensuelles?

Je travaille avec un inventaire mensuel de widgets avec parfois des mois de données manquants. Je voudrais faire une analyse de type «lacunes et îlots» mais je n'arrive pas à faire fonctionner correctement l'implémentation (voir sqlfiddle). J'essaie de créer de nouvelles colonnes répertoriant spécifiquement les dates de début et de fin de l'écart et de l'île:

http://www.sqlfiddle.com/#!18/a212a/2

Toute aide serait appréciée


0 commentaires

3 Réponses :


0
votes

Avec quelques modifications, j'ai converti votre requête en -

WITH StartingPoints AS
(
    SELECT ID, OCCURRANCE, ROW_NUMBER() OVER(ORDER BY OCCURRANCE) AS rn
    FROM dates_test A
    WHERE NOT EXISTS (
        SELECT *
        FROM dates_test B
        WHERE B.ID = A.ID AND EXTRACT(month FROM B.OCCURRANCE) = EXTRACT(month FROM A.OCCURRANCE) - 1)
),
EndingPoints AS
(
    SELECT ID, OCCURRANCE, ROW_NUMBER() OVER(ORDER BY OCCURRANCE) AS rn
    FROM dates_test A
    WHERE NOT EXISTS (
        SELECT *
        FROM dates_test B
        WHERE B.ID = A.ID AND EXTRACT(month FROM B.OCCURRANCE) = EXTRACT(month FROM A.OCCURRANCE) - 1)
)
SELECT S.ID, EXTRACT(month FROM S.OCCURRANCE) AS start_range, EXTRACT(month FROM E.OCCURRANCE) AS end_range
FROM StartingPoints S
JOIN EndingPoints E ON E.ID = S.ID AND E.rn = S.rn;

D'après vous, il semble que vous utilisez Oracle et Oracle ne prend pas en charge les alias de table avec le mot-clé "AS". Si ce n'est pas votre résultat attendu, veuillez également partager votre résultat attendu.

Démo .


1 commentaires

Je suis vraiment désolé, le drapeau oracle était une erreur. Merci d'avoir tenté de résoudre le problème



1
votes

Je pense que vous avez besoin de ce qui suit. violon SQL

                        WITH StartingPoints AS
     (SELECT ID, OCCURRANCE, ROW_NUMBER() OVER(ORDER BY id, OCCURRANCE) AS rn
        FROM dates_test A
       WHERE NOT EXISTS (SELECT *
                FROM dates_test B
               WHERE B.ID = A.ID
                 AND EXTRACT(month FROM B.OCCURRANCE) =
                     EXTRACT(month FROM A.OCCURRANCE) - 1
                 and EXTRACT(year FROM B.OCCURRANCE) =
                     EXTRACT(year FROM A.OCCURRANCE))),
    EndingPoints AS
     (SELECT ID, OCCURRANCE, ROW_NUMBER() OVER(ORDER BY id, OCCURRANCE) AS rn
        FROM dates_test A
       WHERE NOT EXISTS (SELECT *
                FROM dates_test B
               WHERE B.ID = A.ID
                 AND EXTRACT(month FROM B.OCCURRANCE) =
                     EXTRACT(month FROM A.OCCURRANCE) + 1
                 and EXTRACT(year FROM B.OCCURRANCE) =
                     EXTRACT(year FROM A.OCCURRANCE))),
    MissingPoints AS
     (SELECT S.ID,
             EXTRACT(month FROM S.OCCURRANCE) AS start_range,
             EXTRACT(month FROM E.OCCURRANCE) AS end_range,
             EXTRACT(YEAR FROM E.OCCURRANCE) YEAR_of_OCCR
        FROM StartingPoints S
        JOIN EndingPoints E
          ON E.ID = S.ID
         AND E.rn = S.rn),
    i1 as
     (select level num from dual connect by level <= 12),
    ms11 as
     (select ID,
             start_range,
             end_range,
             lead(start_range, 1, 0) OVER(ORDER BY id, year_of_occr, start_range, end_range) as am_i_ms,
             lead(year_of_occr, 1, 0) OVER(ORDER BY id, year_of_occr) as miss_year,
             year_of_occr
        from MissingPoints),
    miss_month1 as
     (select id,
             start_range,
             end_range,
             DECODE(end_range + num, 13, 0, 14, 0, end_range + num) missing_month,
             year_of_occr
        from ms11, i1
       where ((end_range + num < am_i_ms or sTART_Range = end_range) and
             end_range + num <= 14) or (year_of_occr<> miss_year and am_i_ms >=0 and  am_i_ms <=12 and end_range + num <= 14)
       order by year_of_occr, missing_month),
    miss_month as
     (select *
        from miss_month1 A
       where not exists
       (select 1
                from miss_month1 B
               where A.ID = B.ID
                 AND (A.missing_month = B.start_range AND
                     A.missing_month = B.end_range)
                 and A.year_of_occr = B.year_of_occr)
         and decode(end_range, 12, -1, end_range) < missing_month),
    StartingmisPoints AS
     (SELECT A.*,
             ROW_NUMBER() OVER(ORDER BY id, year_of_occr, end_range, missing_month) AS rn
        FROM miss_month A
       WHERE NOT EXISTS (SELECT *
                FROM miss_month B
               WHERE B.ID = A.ID
                 and b.start_range = a.start_range
                 and b.end_range = a.end_range
                 AND B.missing_month = A.missing_month - 1
                 and b.year_of_occr = a.year_of_occr)),
    EndingmisPoints AS
     (SELECT A.*,
             ROW_NUMBER() OVER(ORDER BY id, year_of_occr, end_range, missing_month) AS rn
        FROM miss_month A
       WHERE NOT EXISTS (SELECT *
                FROM miss_month B
               WHERE B.ID = A.ID
                 AND B.missing_month = A.missing_month + 1
                 and b.start_range = a.start_range
                 and b.end_range = a.end_range
                 and b.year_of_occr = a.year_of_occr))
    SELECT distinct  S.ID,
           S.start_range,
           S.end_range,
           S.missing_month start_gap_range,
           E.missing_month end_gap_range,
           E.year_of_occr
      FROM StartingmisPoints S
      JOIN EndingmisPoints E
        ON E.ID = S.ID
       AND E.rn = S.rn

vous pouvez trouver l'écart de début et de fin ci-dessous

  WITH StartingPoints AS
     (SELECT ID, OCCURRANCE, ROW_NUMBER() OVER(ORDER BY id, OCCURRANCE) AS rn
        FROM dates_test A
       WHERE NOT EXISTS (SELECT *
                FROM dates_test B
               WHERE B.ID = A.ID
                 AND EXTRACT(month FROM B.OCCURRANCE) =
                     EXTRACT(month FROM A.OCCURRANCE) - 1
                 and EXTRACT(year FROM B.OCCURRANCE) =
                     EXTRACT(year FROM A.OCCURRANCE))),
    EndingPoints AS
     (SELECT ID, OCCURRANCE, ROW_NUMBER() OVER(ORDER BY id, OCCURRANCE) AS rn
        FROM dates_test A
       WHERE NOT EXISTS (SELECT *
                FROM dates_test B
               WHERE B.ID = A.ID
                 AND EXTRACT(month FROM B.OCCURRANCE) =
                     EXTRACT(month FROM A.OCCURRANCE) + 1
                 and EXTRACT(year FROM B.OCCURRANCE) =
                     EXTRACT(year FROM A.OCCURRANCE)))
    SELECT S.ID,
           EXTRACT(month FROM S.OCCURRANCE) AS start_range,
           EXTRACT(month FROM E.OCCURRANCE) AS end_range
      FROM StartingPoints S
      JOIN EndingPoints E
        ON E.ID = S.ID
       AND E.rn = S.rn;


1 commentaires

Cela se rapproche beaucoup de ce que je recherche. Idéalement, il afficherait le champ de date où l'îlot / espace commence et se termine (par exemple, création de 4 nouvelles colonnes: démarrage / arrêt de l'îlot, démarrage / arrêt de l'écart)



0
votes

Vous pouvez utiliser la fonction analytique LEAD pour trouver les lacunes:

ID | MISSING_FROM        | MISSING_TO         
-: | :------------------ | :------------------
 1 | 2014-03-01 00:00:00 | 2014-03-31 23:59:59
 1 | 2014-09-01 00:00:00 | 2014-10-31 23:59:59
 2 | 2014-03-01 00:00:00 | 2014-03-31 23:59:59
 2 | 2014-09-01 00:00:00 | 2014-10-31 23:59:59

Donc pour vos données de test:

CREATE TABLE dates_test ( id, value, occurrance ) As
-- march and september and october are missing for both IDs-
SELECT 1, 10, DATE '2014-01-03' FROM DUAL UNION ALL
SELECT 1, 10, DATE '2014-02-03' FROM DUAL UNION ALL
SELECT 1, 10, DATE '2014-04-01' FROM DUAL UNION ALL
SELECT 1, 10, DATE '2014-05-01' FROM DUAL UNION ALL
SELECT 1, 10, DATE '2014-06-01' FROM DUAL UNION ALL
SELECT 1, 10, DATE '2014-07-01' FROM DUAL UNION ALL
SELECT 1, 10, DATE '2014-08-01' FROM DUAL UNION ALL
SELECT 1, 10, DATE '2014-11-07' FROM DUAL UNION ALL
SELECT 1, 10, DATE '2014-12-07' FROM DUAL UNION ALL
SELECT 1, 10, DATE '2015-01-07' FROM DUAL UNION ALL
SELECT 2, 10, DATE '2014-01-03' FROM DUAL UNION ALL
SELECT 2, 10, DATE '2014-02-03' FROM DUAL UNION ALL
SELECT 2, 10, DATE '2014-04-01' FROM DUAL UNION ALL
SELECT 2, 10, DATE '2014-05-01' FROM DUAL UNION ALL
SELECT 2, 10, DATE '2014-06-01' FROM DUAL UNION ALL
SELECT 2, 10, DATE '2014-07-01' FROM DUAL UNION ALL
SELECT 2, 10, DATE '2014-08-01' FROM DUAL UNION ALL
SELECT 2, 10, DATE '2014-11-07' FROM DUAL UNION ALL
SELECT 2, 10, DATE '2014-12-07' FROM DUAL UNION ALL
SELECT 2, 10, DATE '2015-01-07' FROM DUAL;


0 commentaires