2013-01-10 43 views
10

Trong oracle tôi có thể tìm ra không: của tháng giữa sử dụng chức năng MONTHS_BETWEEN.Tháng giữa hai ngày chức năng

Trong postgres tôi đang sử dụng chức năng trích xuất cho việc này. ví dụ: như

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

Có cách nào khác (được xây dựng trong chức năng) ở bưu điện không ??

+0

thậm chí tôi đã sử dụng cùng một cách –

Trả lời

3

Rất tiếc, có vẻ như không, bởi vì extract(month ...) trả về số tháng modulo 12.

Có một đơn giản hóa nhỏ mà bạn có thể thực hiện; loại bỏ các tham số đầu tiên của age() - mặc định là độ tuổi từ current_date, vì vậy hai đều tương đương:

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

'tuổi ('2012-12-09')' sẽ tạo ra lỗi (postgresql 9.2.1) do loại đối số không xác định. Tôi cần phải xác định 'age ('2012-12-09' :: date)' – araqnid

1

Bạn có thể sử dụng UDF, ví dụ Tôi đã tìm thấy sau 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

Gần đây tôi đã làm việc với một nhà phát triển mới bao gồm chức năng này cho cơ sở dữ liệu của chúng tôi để thực hiện một số công việc và tôi có thể làm chứng rằng SUCKS, nó rất chậm, không được tối ưu hóa, việc biểu diễn rất tệ. Nó có thể đa mục đích, nhưng không phải là một giải pháp tốt. Chỉ cần thử so sánh đơn giản này: tuổi (ngày sinh) chống lại chức năng này. – FiruzzZ

10

này rất dễ dàng để tái thực hiện trong PostgreSQL chỉ sử dụng chức năng SQL để dọn dẹp những gì bạn đã có:

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

Và bây giờ select months_between('1978-06-20', '2011-12-09') sản xuất 401

+6

"Tháng" là một thuật ngữ mờ, và tiếc là nó không nhận được ít mờ khi bạn quấn một chức năng xung quanh nó. Sử dụng 'months_between ('2012-01-01', '2012-01-31')' trả về 0 cho khoảng thời gian 30 ngày đó. Nhưng sử dụng 'months_between ('2012-02-01', '2012-03-01')' trả về 1 cho khoảng thời gian 29 ngày đó. Câu chuyện ngắn là bạn * nên * để xác định những gì "tháng" có nghĩa là trong ứng dụng của bạn trước khi bạn bắt đầu viết mã. –

+1

@Catcall Cảm nhận của bạn là khá hợp lệ nhưng không nên được hướng dẫn tại OP? mã của araqnid hoạt động chính xác như mã của OP, vì vậy tôi cho rằng đó là những gì anh ta muốn. –

+4

Tôi không biết. Tôi upvoted câu trả lời của araqnid. Theo kinh nghiệm của tôi, hầu hết những người sử dụng các chức năng như thế này * không * nghĩ về những gì * tháng * hoặc * số tuần * nên có nghĩa là trong ứng dụng của họ. Họ chỉ sử dụng bất cứ điều gì họ tìm thấy. (Đó là một quan sát, không phải là một lời chỉ trích.) OP đã không chấp nhận một câu trả lời, vì vậy tôi hy vọng anh ta hoặc cô ấy để đọc tất cả những thứ này sớm hay muộn. Có lẽ tôi lạc quan không thực tế. –

0
SELECT date_part ('year', f) * 12 
     + date_part ('month', f) 
FROM age (CURRENT_DATE, '2014-12-01') f 
Các vấn đề liên quan