2013-01-10 6 views
10

In oracle posso trovare no: di mesi tra l'utilizzo della funzione MONTHS_BETWEEN.Mesi tra due date funzione

In postgres sto usando la funzione di estrazione per questo. eg.like

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

c'è qualche altro modo (costruito nel funzioni) in Postgres ??

+0

anche ho usato allo stesso modo –

risposta

3

Sfortunatamente non sembra, perché extract(month ...) restituisce il numero di mesi modulo 12.

C'è una piccola semplificazione che è possibile effettuare; rimuovere il primo parametro del age() - il default è l'età da current_date, così questi due sono equivalenti:

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

'età ('2012/12/09')' produrrà un errore (PostgreSQL 9.2.1) a causa del tipo di argomento sconosciuto. Devi specificare 'age ('2012-12-09' :: date)' – araqnid

1

È possibile utilizzare UDF, ad esempio, Ho trovato il seguente 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

Recentemente ho lavorato con un nuovo sviluppatore che includeva questa funzione nei nostri database per fare alcuni lavori e posso testimoniare che SUCKS, è estremamente lento, no ottimizzato, il rendimento è così grave. Può essere multiuso, ma non è una buona soluzione. Basta provare questo semplice confronto: età (data di nascita) contro questa funzione. – FiruzzZ

10

Questo è facile da re-implementare in PostgreSQL solo utilizzando funzioni SQL per riordinare quello che hai già:

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))) 
$$; 

E ora select months_between('1978-06-20', '2011-12-09') produce 401 .

+6

"Month" è un termine fuzzy e sfortunatamente non diventa meno sfocato quando si avvolge una funzione attorno ad esso. L'utilizzo di 'months_between ('2012-01-01', '2012-01-31')' restituisce 0 per quell'intervallo di 30 giorni. Ma usando 'months_between ('2012-02-01', '2012-03-01')' restituisce 1 per quell'intervallo di 29 giorni. La storia breve è che * dovresti * definire cosa significa "mese" nella tua applicazione prima di iniziare a scrivere codice. –

+1

@Catcall Il tuo commento è abbastanza valido ma non dovrebbe essere diretto all'OP? Il codice di araqnid si comporta esattamente come fa il codice dell'OP, quindi suppongo che sia quello che vuole. –

+4

Non lo so. Ho svalutato la risposta di araqnid. Nella mia esperienza, la maggior parte delle persone che usano funzioni come questa * non * pensa a quale * mese * o * numero della settimana * dovrebbe significare nella loro applicazione. Usano solo quello che trovano. (Questa è un'osservazione, non una critica.) L'OP non ha accettato una risposta, quindi mi aspetto che lui o lei leggano tutte queste cose prima o poi. Forse sono irrealisticamente ottimista. –

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