Sqlserver
 sql >> Teknologi Basis Data >  >> RDS >> Sqlserver

Solusi untuk DATEDIFF() Mengabaikan SET DATEFIRST di SQL Server (Contoh T-SQL)

Hal yang menarik tentang DATEDIFF() fungsi di SQL Server adalah mengabaikan SET DATEFIRST nilai.

Namun, ini bukan bug. Dokumentasi Microsoft untuk DATEDIFF() dengan jelas menyatakan sebagai berikut:

Menentukan SET DATEFIRST tidak berpengaruh pada DATEDIFF . DATEDIFF selalu menggunakan hari Minggu sebagai hari pertama dalam seminggu untuk memastikan fungsi beroperasi secara deterministik.

Jika Anda tidak tahu, SET DATEFIRST menetapkan hari pertama dalam seminggu untuk sesi Anda. Ini adalah angka dari 1 hingga 7 (yang sesuai dengan Senin hingga Minggu).

Nilai awal untuk SET DATEFIRST secara implisit diatur oleh pengaturan bahasa (yang dapat Anda atur dengan SET LANGUAGE penyataan). Nilai sebenarnya akan tergantung pada bahasa yang disetel. Misalnya nilai default untuk us_english bahasa 7 (Minggu), sedangkan default untuk British bahasanya adalah 1 (Senin).

Namun, Anda dapat menggunakan SET DATEFIRST pernyataan untuk menimpa ini sehingga Anda dapat tetap menggunakan bahasa yang sama saat menggunakan hari yang berbeda untuk hari pertama dalam seminggu.

Tapi seperti yang disebutkan, SET DATEFIRST nilai tidak berpengaruh pada DATEDIFF() fungsi. DATEDIFF() fungsi selalu mengasumsikan bahwa hari Minggu adalah hari pertama dalam seminggu terlepas dari SET DATEFIRST Anda nilai.

Ini dapat menyebabkan beberapa masalah menarik saat menggunakan DATEDIFF() jika Anda tidak tahu cara kerjanya.

Jika Anda berada dalam situasi ini, semoga contoh di halaman ini dapat membantu.

Contoh 1 – Masalah

Pertama, inilah contoh masalah yang sebenarnya. Perhatikan bahwa kita dapat mengambil SET DATEFIRST nilai dengan memilih @@DATEFIRST .

DECLARE @startdate date ='2025-01-05', @enddate date ='2025-01-06';SET LANGUAGE us_english;SELECT @@DATEFIRST AS 'SET DATEFIRST Value', DATEDIFF(week, @startdate, @enddate) AS 'us_english DATEDIFF() Result';SET LANGUAGE British;SELECT @@DATEFIRST AS 'SET DATEFIRST Value', DATEDIFF(week, @startdate, @enddate) AS 'British DATEDIFF() Result';

Hasil:

+------------------------+----------------------- ----------+| SET DATEFIRST Nilai | us_english TANGGAL() Hasil ||-----------------------+------------------- -------------|| 7 | 0 |+-----------------------+----------------------- ---------++-----------------------+--------------- --------------+| SET DATEFIRST Nilai | British DATEDIFF() Hasil ||-----------------------+------------------- ----------|| 1 | 0 |+-----------------------+----------------------- ------+

Dalam hal ini, kencan pertama jatuh pada hari Minggu dan kencan kedua pada hari Senin. Oleh karena itu, Anda biasanya mengharapkan DATEDIFF() British Inggris hasil untuk mengembalikan 1 . Anda akan mengharapkan ini karena batas bagian minggu dilintasi saat berlangsung dari Minggu hingga Senin (karena SET DATEFIRST nilainya 1 yang berarti “Senin”, dan Senin menandai awal minggu baru).

Tapi karena DATEDIFF() mengabaikan SET DATEFIRST nilai dan menganggap bahwa hari Minggu adalah awal minggu, kami mendapatkan hasil yang sama untuk kedua bahasa.

Untuk memastikan, saya akan menjalankan kueri lagi, tetapi kali ini saya akan mengatur SET DATEFIRST nilai secara eksplisit . Dengan kata lain, alih-alih mengatur bahasa, saya akan menggunakan SET DATEFIRST pernyataan:

DECLARE @startdate date ='2025-01-05', @enddate date ='2025-01-06';SET DATEFIRST 7;SELECT @@DATEFIRST AS 'SET DATEFIRST Value', DATEDIFF(minggu, @startdate, @enddate) AS 'us_english DATEDIFF() Result';SET DATEFIRST 1;SELECT @@DATEFIRST AS 'SET DATEFIRST Value', DATEDIFF(week, @startdate, @enddate) AS 'British DATEDIFF() Result';

Hasil:

+------------------------+----------------------- ----------+| SET DATEFIRST Nilai | us_english TANGGAL() Hasil ||-----------------------+------------------- -------------|| 7 | 0 |+-----------------------+----------------------- ---------++-----------------------+--------------- --------------+| SET DATEFIRST Nilai | British DATEDIFF() Hasil ||-----------------------+------------------- ----------|| 1 | 0 |+-----------------------+----------------------- ------+

Hasil yang sama, bahkan ketika Anda secara eksplisit menyetel SET DATEFIRST nilai. Ini tidak mengherankan – saya akan terkejut jika tidak mengembalikan hasil yang sama.

Selain itu, ini hanya mengonfirmasi bahwa DATEDIFF() bekerja persis seperti yang dimaksudkan.

Jadi, bagaimana kita mengubahnya sehingga DATEDIFF() . kita hasil menghormati SET DATEFIRST . kami nilai?

Solusinya

Inilah solusi/solusi yang memungkinkan Anda mendapatkan hasil yang diinginkan. Ini akan memastikan bahwa SET DATEFIRST pengaturan diperhitungkan ke dalam DATEDIFF() . Anda hasil.

Yang perlu Anda lakukan adalah mengurangi @@DATEFIRST dari tanggal input.

DECLARE @startdate date ='2025-01-05', @enddate date ='2025-01-06';SET DATEFIRST 7;SELECT @@DATEFIRST AS 'SET DATEFIRST Value', DATEDIFF(minggu, DATEADD(hari , [email protected]@DATEFIRST, @startdate), DATEADD(day, [email protected]@DATEFIRST, @enddate)) AS 'us_english DATEDIFF() Hasil';SET DATEFIRST 1;SELECT @@DATEFIRST AS 'SET DATEFIRST Nilai', DATEDIFF(minggu, DATEADD(hari, [email protected]@DATEFIRST, @tanggal mulai), DATEADD(hari, [email protected]@DATEFIRST, @tanggal akhir)) AS 'British DATEDIFF() Hasil'; 

Hasil:

+------------------------+----------------------- ----------+| SET DATEFIRST Nilai | us_english TANGGAL() Hasil ||-----------------------+------------------- -------------|| 7 | 0 |+-----------------------+----------------------- ---------++-----------------------+--------------- --------------+| SET DATEFIRST Nilai | British DATEDIFF() Hasil ||-----------------------+------------------- ----------|| 1 | 1 |+-----------------------+----------------------- ------+

Ini menggunakan DATEADD() berfungsi untuk mengurangi tanggal input dengan jumlah @@DATEFIRST (yang merupakan SET DATEFIRST . Anda nilai).

Dalam hal ini DATEDIFF() fungsi masih menggunakan hari Minggu sebagai hari pertama dalam seminggu, namun, tanggal aktual yang digunakan dalam perhitungan berbeda. Mereka telah dipindahkan kembali ke masa lalu dengan jumlah @@DATEFIRST .

Contoh berikut menunjukkan tanggal yang digunakan dalam perhitungan:

DECLARE @startdate date ='2025-01-05', @enddate date ='2025-01-06';SET DATEFIRST 7;SELECT @startdate AS 'Original Date', @@DATEFIRST SEBAGAI 'Kurangi', DATEADD(hari, [email protected]@DATEFIRST, @startdate) SEBAGAI 'Resulting Date'UNION ALLSELECT @enddate, @@DATEFIRST, DATEADD(day, [email protected]@DATEFIRST, @enddate); SET DATEFIRST 1;PILIH @startdate SEBAGAI 'Tanggal Asli', @@DATEFIRST SEBAGAI 'Kurangi Dengan', DATEADD(hari, [email protected]@DATEFIRST, @startdate) SEBAGAI 'Tanggal Hasil'UNION ALLSELECT @enddate, @@DATEFIRST , DATEADD(hari, [email protected]@DATEFIRST, @enddate); 

Hasil:

+-----------------+---------------+------------ ------+| Tanggal Asli | Kurangi Dengan | Tanggal Hasil ||-----------------+---------------+------------ ------|| 2025-01-05 | 7 | 2024-12-29 || 2025-01-06 | 7 | 2024-12-30 |+-------+---------------+-------- ---------++-----------------+---------------+----- -------------+| Tanggal Asli | Kurangi Dengan | Tanggal Hasil ||-----------------+---------------+------------ ------|| 2025-01-05 | 1 | 2025-01-04 || 2025-01-06 | 1 | 2025-01-05 |+-----------------+---------------+-------- ---------+

Jadi dalam solusi kami, DATEDIFF() menggunakan "Tanggal Hasil" dalam perhitungannya.

Jika Anda mengalami masalah dengan DATEDIFF() mengabaikan SET DATEFIRST , semoga artikel ini membantu.


  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. Atur susunan basis data dalam Entity Framework Code-First Initializer

  2. dapatkan string yang dipisahkan koma dari baris

  3. SQL Server AlwaysOn Availability Groups:Instalasi dan konfigurasi, Bagian 1

  4. Cara Menemukan Kumpulan Basis Data yang Didukung oleh Instans SQL Server Anda

  5. INFORMATION_SCHEMA vs sysobjects