Saya mencari cara untuk menerapkan fungsi-SQLServer tanggaliff di PostgreSQL. Itu adalah,
Fungsi ini mengembalikan hitungan (sebagai nilai integer bertanda) dari batas bagian tanggal yang disilangkan antara tanggal mulai dan tanggal akhir yang ditentukan.
datediff(dd, '2010-04-01', '2012-03-05') = 704 // 704 changes of day in this interval
datediff(mm, '2010-04-01', '2012-03-05') = 23 // 23 changes of month
datediff(yy, '2010-04-01', '2012-03-05') = 2 // 2 changes of year
Saya tahu saya bisa melakukan 'dd' hanya dengan menggunakan substraksi, tetapi ada ide tentang dua lainnya?
postgresql
date
gefei
sumber
sumber
Jawaban:
SELECT AGE('2012-03-05', '2010-04-01'), DATE_PART('year', AGE('2012-03-05', '2010-04-01')) AS years, DATE_PART('month', AGE('2012-03-05', '2010-04-01')) AS months, DATE_PART('day', AGE('2012-03-05', '2010-04-01')) AS days;
Ini akan memberi Anda tahun penuh , bulan, hari ... antara dua tanggal:
age | years | months | days -----------------------+-------+--------+------ 1 year 11 mons 4 days | 1 | 11 | 4
Informasi dateiff lebih rinci .
sumber
select date_part('month', age('2010-04-01', '2012-03-05'));
memberi-11
. Itu bukan perbedaan bulan yang tepatSELECT date_part('day', age('2016-10-05', '2015-10-02'))
pengembalian3
age()
akan selalu salah untuk melakukan ini selama bertahun-tahun dan berbulan-bulan. Antara2014-12-31
dan2015-01-01
lalu akan memberi 0 untuk bulan dan tahun, sementaradatediff()
akan memberi 1 dan 1. Anda tidak bisa hanya menambahkan satu keage()
hasil karenaage()+1
akan memberi 1 saat antara2015-01-01
dan2015-01-02
, sedangkandatediff()
sekarang akan memberi 0.Kurangi saja:
SELECT ('2015-01-12'::date - '2015-01-01'::date) AS days;
Hasil:
days ------ 11
sumber
range_end - range_start ASC, id DESC
interval
, yang tidak bisa begitu saja dilemparkan sebagaiint
. Bagaimana cara mengubah interval menjadi beberapa jam dengan postgres? . Menggunakandate_part
/age
function combo, seperti yang disebutkan dalam jawaban @IgorRomanchenko akan mengembalikan tipedouble precision
date_part
/age
, seperti yang diterima, akan memberikan hari sebagai perbedaan pada bagian hari dari dua tanggal.date_part('day', age('2016-9-05', '2015-10-02'))
mengembalikan 3.Saya menghabiskan beberapa waktu mencari jawaban terbaik, dan saya rasa saya memilikinya.
Sql ini akan memberi Anda jumlah hari antara dua tanggal sebagai
integer
:SELECT (EXTRACT(epoch from age('2017-6-15', now())) / 86400)::int
..yang, ketika dijalankan hari ini (
2017-3-28
), memberi saya:?column? ------------ 77
Kesalahpahaman tentang jawaban yang diterima:
select age('2010-04-01', '2012-03-05'), date_part('year',age('2010-04-01', '2012-03-05')), date_part('month',age('2010-04-01', '2012-03-05')), date_part('day',age('2010-04-01', '2012-03-05'));
..adalah Anda akan mendapatkan perbedaan literal antara bagian-bagian string tanggal, bukan jumlah waktu antara dua tanggal.
YAITU:
Age(interval)=-1 years -11 mons -4 days;
Years(double precision)=-1;
Months(double precision)=-11;
Days(double precision)=-4;
sumber
Fungsi yang hampir sama dengan yang Anda butuhkan (berdasarkan jawaban atiruz, versi singkat UDF dari sini )
CREATE OR REPLACE FUNCTION datediff(type VARCHAR, date_from DATE, date_to DATE) RETURNS INTEGER LANGUAGE plpgsql AS $$ DECLARE age INTERVAL; BEGIN CASE type WHEN 'year' THEN RETURN date_part('year', date_to) - date_part('year', date_from); WHEN 'month' THEN age := age(date_to, date_from); RETURN date_part('year', age) * 12 + date_part('month', age); ELSE RETURN (date_to - date_from)::int; END CASE; END; $$;
Pemakaian:
/* Get months count between two dates */ SELECT datediff('month', '2015-02-14'::date, '2016-01-03'::date); /* Result: 10 */ /* Get years count between two dates */ SELECT datediff('year', '2015-02-14'::date, '2016-01-03'::date); /* Result: 1 */ /* Get days count between two dates */ SELECT datediff('day', '2015-02-14'::date, '2016-01-03'::date); /* Result: 323 */ /* Get months count between specified and current date */ SELECT datediff('month', '2015-02-14'::date, NOW()::date); /* Result: 47 */
sumber
DATEDIFF()
fungsi dalam MS SQL kembali1
untukdatediff(year, '2015-02-14', '2016-01-03')
. Ini karena Anda harus melewati batas tahun satu kali di antara tanggal-tanggal tersebut: docs.microsoft.com/en-us/sql/t-sql/functions/…SELECT date_part ('year', f) * 12 + date_part ('month', f) FROM age ('2015-06-12'::DATE, '2014-12-01'::DATE) f
Hasil: 6
sumber
Pertanyaan ini penuh dengan kesalahpahaman. Pertama mari kita pahami pertanyaannya sepenuhnya. Penanya ingin mendapatkan hasil yang sama seperti ketika menjalankan fungsi MS SQL Server
DATEDIFF ( datepart , startdate , enddate )
di manadatepart
dibutuhkandd
,mm
atauyy
.Fungsi ini ditentukan oleh:
Itu berarti berapa banyak batas hari, bulan, atau tahun, dilintasi. Bukan berapa hari, bulan, atau tahun di antara mereka. Itu sebabnya
datediff(yy, '2010-04-01', '2012-03-05')
adalah 2, dan bukan 1. Ada waktu kurang dari 2 tahun di antara tanggal-tanggal tersebut, artinya hanya 1 tahun penuh yang telah berlalu, tetapi batas 2 tahun telah dilintasi, dari 2010 ke 2011, dan dari 2011 ke 2012.Berikut ini adalah upaya terbaik saya untuk mereplikasi logika dengan benar.
-- datediff(dd`, '2010-04-01', '2012-03-05') = 704 // 704 changes of day in this interval select ('2012-03-05'::date - '2010-04-01'::date ); -- 704 changes of day -- datediff(mm, '2010-04-01', '2012-03-05') = 23 // 23 changes of month select (date_part('year', '2012-03-05'::date) - date_part('year', '2010-04-01'::date)) * 12 + date_part('month', '2012-03-05'::date) - date_part('month', '2010-04-01'::date) -- 23 changes of month -- datediff(yy, '2010-04-01', '2012-03-05') = 2 // 2 changes of year select date_part('year', '2012-03-05'::date) - date_part('year', '2010-04-01'::date); -- 2 changes of year
sumber
Saya ingin memperluas jawaban Riki_tiki_tavi dan mendapatkan datanya di luar sana. Saya telah membuat fungsi Dateiff yang melakukan hampir semua yang dilakukan sql server. Dengan begitu kita bisa memperhitungkan unit apa saja.
create function datediff(units character varying, start_t timestamp without time zone, end_t timestamp without time zone) returns integer language plpgsql 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; $$;
sumber
Jawaban @WebWanderer sangat mirip dengan DateDiff menggunakan SQL server, tetapi tidak akurat. Itu karena penggunaan fungsi age ().
misalnya hari antara '2019-07-29' dan '2020-06-25' harus menghasilkan 332, namun, menggunakan fungsi age () akan mengembalikan 327. Karena age () mengembalikan '10 mons 27 hari "dan memperlakukannya setiap bulan sebagai 30 hari yang salah.
Anda harus menggunakan stempel waktu untuk mendapatkan hasil yang akurat. misalnya
ceil((select extract(epoch from (current_date::timestamp - <your_date>::timestamp)) / 86400))
sumber
Berikut adalah contoh lengkap dengan keluaran. psql (10.1, server 9.5.10).
Anda mendapatkan 58, bukan nilai kurang dari 30.
Hapus fungsi age (), memecahkan masalah yang disebutkan posting sebelumnya.
drop table t; create table t( d1 date ); insert into t values(current_date - interval '58 day'); select d1 , current_timestamp - d1::timestamp date_diff , date_part('day', current_timestamp - d1::timestamp) from t; d1 | date_diff | date_part ------------+-------------------------+----------- 2018-05-21 | 58 days 21:41:07.992731 | 58
sumber
Satu solusi lagi, versi untuk perbedaan 'tahun':
SELECT count(*) - 1 FROM (SELECT distinct(date_trunc('year', generate_series('2010-04-01'::timestamp, '2012-03-05', '1 week')))) x
(1 baris)
Dan trik yang sama selama berbulan-bulan:
SELECT count(*) - 1 FROM (SELECT distinct(date_trunc('month', generate_series('2010-04-01'::timestamp, '2012-03-05', '1 week')))) x
(1 baris)
Dalam kueri kehidupan nyata mungkin ada beberapa urutan timestamp yang dikelompokkan berdasarkan jam / hari / minggu / dll, bukan generate_series.
Ini
'count(distinct(date_trunc('month', ts)))'
dapat digunakan tepat di sisi 'kiri' pilihan:SELECT sum(a - b)/count(distinct(date_trunc('month', c))) FROM d
Saya menggunakan generate_series () di sini hanya untuk singkatnya.
sumber