2013-01-10 14 views
10

W wyroczni mogę stwierdzić, nie: miesięcy między używaniem funkcji MONTHS_BETWEEN.Miesiące między dwiema datami funkcja

W postgresach używam do tego funkcji wyodrębniania. eg.like

select 
    extract(year from age(current_date, '2012-12-09')) * 12 
    + 
    extract(month from age(current_date, '2012-12-09')) 

Czy są jakieś inne sposoby (zbudowany w funkcji) w PostgreSQL ??

+0

nawet użyłem w ten sam sposób –

Odpowiedz

3

Niestety nie wydaje się, ponieważ extract(month ...) zwraca liczbę miesięcy modulo 12.

Istnieje jedno małe uproszczenie, które możesz wykonać; usunąć pierwszy parametr age() - domyślnie jest to wiek od current_date, więc te dwa są równoważne:

age(current_date, '2012-12-09') 
age('2012-12-09') 
+0

'wiek ('2012-12-09')' będzie produkować błąd (postgresql 9.2.1) z powodu nieznanego typu argumentów. Musisz podać 'age (' 2012-12-09 ':: date) ' – araqnid

1

Można użyć UDF, np Znalazłem następujące here:

CREATE OR REPLACE FUNCTION DateDiff (units VARCHAR(30), start_t TIMESTAMP, end_t TIMESTAMP) 
    RETURNS INT AS $$ 
    DECLARE 
    diff_interval INTERVAL; 
    diff INT = 0; 
    years_diff INT = 0; 
    BEGIN 
    IF units IN ('yy', 'yyyy', 'year', 'mm', 'm', 'month') THEN 
     years_diff = DATE_PART('year', end_t) - DATE_PART('year', start_t); 

     IF units IN ('yy', 'yyyy', 'year') THEN 
     -- SQL Server does not count full years passed (only difference between year parts) 
     RETURN years_diff; 
     ELSE 
     -- If end month is less than start month it will subtracted 
     RETURN years_diff * 12 + (DATE_PART('month', end_t) - DATE_PART('month', start_t)); 
     END IF; 
    END IF; 

    -- Minus operator returns interval 'DDD days HH:MI:SS' 
    diff_interval = end_t - start_t; 

    diff = diff + DATE_PART('day', diff_interval); 

    IF units IN ('wk', 'ww', 'week') THEN 
     diff = diff/7; 
     RETURN diff; 
    END IF; 

    IF units IN ('dd', 'd', 'day') THEN 
     RETURN diff; 
    END IF; 

    diff = diff * 24 + DATE_PART('hour', diff_interval); 

    IF units IN ('hh', 'hour') THEN 
     RETURN diff; 
    END IF; 

    diff = diff * 60 + DATE_PART('minute', diff_interval); 

    IF units IN ('mi', 'n', 'minute') THEN 
     RETURN diff; 
    END IF; 

    diff = diff * 60 + DATE_PART('second', diff_interval); 

    RETURN diff; 
    END; 
    $$ LANGUAGE plpgsql; 
+0

Niedawno pracowałem z nowym programistą, który włączył tę funkcję do naszych baz danych, aby wykonać pewne zadania i mogę potwierdzić, że SUCKS jest bardzo wolny, nie zoptymalizowany, wykonanie jest tak źle. Może to być wielofunkcyjny, ale nie jest dobrym rozwiązaniem. Po prostu spróbuj tego prostego porównania: wiek (data urodzenia) w odniesieniu do tej funkcji. – FiruzzZ

10

Jest to łatwe do ponownego wdrożenia w PostgreSQL tylko przy użyciu funkcji SQL posprzątać to, co już masz:

create function months_of(interval) 
returns int strict immutable language sql as $$ 
    select extract(years from $1)::int * 12 + extract(month from $1)::int 
$$; 

create function months_between(date, date) 
returns int strict immutable language sql as $$ 
    select abs(months_of(age($1, $2))) 
$$; 

A teraz select months_between('1978-06-20', '2011-12-09') produkuje 401 .

+6

"Miesiąc" jest terminem rozmytym i niestety nie staje się mniej rozmytym, gdy otoczysz nim funkcję. Użycie 'months_between ('2012-01-01', '2012-01-31')' zwraca 0 dla tego 30-dniowego okresu. Ale użycie 'months_between ('2012-02-01', '2012-03-01')' zwraca 1 dla tego 29-dniowego okresu. Krótko mówiąc, musisz * zdecydować *, aby zdefiniować, co "miesiąc" oznacza w twojej aplikacji, zanim zaczniesz pisać kod. –

+1

@Catcall Twój komentarz jest poprawny, ale czy nie powinien być skierowany na PO? Kod araqnida zachowuje się dokładnie tak samo jak kod OP, więc przypuszczam, że właśnie tego chce. –

+4

Nie wiem. Przegłosowałem odpowiedź araqnida. Z mojego doświadczenia wynika, że ​​większość ludzi, którzy używają takich funkcji * nie zastanawia się, co * miesiąc * lub * numer tygodnia * powinno oznaczać w ich aplikacji. Używają tylko tego, co znajdą. (To spostrzeżenie, a nie krytyka.) PO nie przyjął odpowiedzi, więc spodziewam się, że wcześniej czy później przeczyta to wszystko. Może jestem nierealistycznie optymistą. –

0
SELECT date_part ('year', f) * 12 
     + date_part ('month', f) 
FROM age (CURRENT_DATE, '2014-12-01') f 
Powiązane problemy