2009-10-05 13 views
5

Mam zestaw danych, który zawiera:PostgreSQL i sekwencyjne danych

Table { date itemName } 

data w przeważającej części jest sekwencyjna. Nie ma duplikatów daty [ponieważ jest to klucz podstawowy].

Pytanie jest podzielony na kilka części (wszystko w odniesieniu do korzystania z SQL):

  1. Czy to możliwe, aby znaleźć luki w serii dat wymienionych w tabeli? Na przykład: Brak dat 1/2/09-1/3/09
  2. Czy można znaleźć sekcje dat, których brakuje w tabeli, która ma zakres większy niż n (jest to liczba określona w czasie wykonywania)? Na przykład: Dla n = 2 Daty 1/2/09-1/3/09 nie są zwracane, ale datą są 5/6/09-6/1/09.
+0

Moje podejście byłoby postprocesowego wyniki .. http://jeremy.zawodny.com/blog/archives/010523.html .. ale jeśli jest to możliwe w zapytaniu i nie uderzy zbyt mocno w system, to byłoby wspaniale :) – warren

+0

To nie jest zapytanie na żywo, które będzie często używane, tylko do konserwacji co jeden raz i chwila. – monksy

Odpowiedz

1

Po prostu utwórz funkcję w plsql lub w kliencie, który będzie sprawdzał wszystkie daty. Podobnie jak ten pseudokod:

date checked_date = 2000-01-01; 
int unchecked_section = 0; 
while (checked_date <= today()) { 
    if (! sql(select itemName from Table where itemName=checked_date)) { 
    unchecked_section++; 
    } else { 
    if (unchecked_section>=n) { 
     print checked_date-unchecked_section, checked_date 
    } 
    unchecked_section = 0; 
    } 
    checked_date++; 
} 
if (unchecked_section) { 
    print checked_date-unchecked_section, checked_date 
} 

Nie musi być bardzo szybki, ponieważ jest to tylko konserwacja. Nie ma wielu dat do sprawdzenia - tylko 365 rocznie.

+0

Jeśli nie masz dostępnych funkcji okna SQL, to jest to najszybsze z możliwych w dużym zestawie danych, ponieważ powoduje tylko jedno przejście przez tabelę. Jedną rzeczą, którą musisz obejrzeć, jest to, że SELECT dostaje ORDER BY, więc wiersze pojawiają się w posortowanej kolejności. I powinieneś użyć "SELECT min (data), max (data) z tabeli", aby uzyskać limity pętli - zakładanie, że rzeczy kończą się na "dzisiaj", nie jest najlepszym pomysłem. PostgreSQL posiada wiele języków programowania, które można uruchomić w bazie danych, PL/pgSQL jest standardową. –

1

Po pewnym testów wymyśliłem następującą instrukcję SQL:

SELECT date, itemName 
    FROM "Table" as t1 
    WHERE NOT EXISTS (
    SELECT date 
    FROM "Table" as t2 
    WHERE t2.date = (t1.date - INTERVAL '1 day') 
) 
    ORDER BY date 
    OFFSET 1 -- this will skip the first element 

To będzie Ci wszystkie wiersze, które nie mają bezpośredniego następcę.

Jeśli zmodyfikować oświadczenie:

SELECT date, itemName 
    FROM "Table" as t1 
    WHERE NOT EXISTS (
    SELECT date 
    FROM "Table" as t2 
    WHERE (t2.date >= (t1.date - INTERVAL '2 day')) 
    AND (t2.date < t1.date) 
) 
    ORDER BY date 
    OFFSET 1 

można użyć długości odstępu w klauzuli WHERE w podselekcji do filtrowania przez luk co najmniej równym wielkości.

Nadzieję, że pomaga.

+0

Środowisko wykonawcze jest proporcjonalne do kwadratu rozmiaru tabeli, ponieważ zarówno zewnętrzne SELECT, jak i wewnętrzne podzapytanie EXISTS, wykonują czynności, których czas wykonywania jest proporcjonalny do rozmiaru tabeli. To może wydawać się rozsądne na początku, ale ostatecznie stanie się naprawdę drogie. Niestety, każde inne rozwiązanie, które robisz w prostym SQL, będzie cierpieć z tego samego problemu, ponieważ SQL nie ma pamięci wiersza. W przypadku tabeli z jednym wierszem musisz wykonać polecenie n X n dołączyć do jakiegoś sposobu rozwiązania tego typu problemu. Gdy są dostępne, funkcje okna są najlepsze w tym zakresie. –

+0

@Greg: Dzięki za analizę.masz rację, to nie jest najszybsze rozwiązanie, jeśli masz dostęp do okien. Ale PostgreSQL 8.4 jest całkiem nowym wydaniem, więc są szanse, że OP używa starszej wersji. Zobacz także komentarz do programu operacyjnego dotyczący jego pytania pod kątem wymagań wydajności środowiska wykonawczego. –

10

Jeśli można użyć PostgreSQL 8.4 następnie window functions pomoże:

SELECT * 
    FROM (SELECT itemName, date, date - lag(date) OVER w AS gap 
       FROM someTable WINDOW w AS (ORDER BY date) 
     ) AS pairs 
    WHERE pairs.gap > '1 day'::interval; 
+0

Jest to dokładnie ten rodzaj problemów, które funkcje okien mają zamiar rozwiązać skutecznie, i nie ma innego rozwiązania tylko SQL, które może działać tak szybko, jak to. –

+0

Niestety, nie mam wersji 8.4. Mam 8.1. Chciałabym móc przyznać się do tej odpowiedzi. Naprawdę to lubie. – monksy