Một điều thú vị về DATEDIFF()
trong SQL Server là nó bỏ qua SET DATEFIRST
của bạn giá trị.
Tuy nhiên, đây không phải là một lỗi. Tài liệu của Microsoft cho DATEDIFF()
nêu rõ những điều sau:
Chỉ định
SET DATEFIRST
không ảnh hưởng đếnDATEDIFF
.DATEDIFF
luôn sử dụng Chủ nhật là ngày đầu tiên trong tuần để đảm bảo chức năng hoạt động một cách xác định.
Trong trường hợp bạn không biết, hãy SET DATEFIRST
đặt ngày đầu tiên trong tuần cho phiên của bạn. Đó là một số từ 1 đến 7 (tương ứng với Thứ Hai đến Chủ Nhật).
Giá trị ban đầu cho SET DATEFIRST
được đặt ngầm bởi cài đặt ngôn ngữ (mà bạn có thể đặt bằng SET LANGUAGE
tuyên bố). Giá trị thực tế sẽ phụ thuộc vào ngôn ngữ được đặt. Ví dụ:giá trị mặc định cho us_english
ngôn ngữ là 7
(Chủ nhật), trong khi mặc định cho British
ngôn ngữ là 1
(Thứ hai).
Tuy nhiên, bạn có thể sử dụng SET DATEFIRST
để ghi đè câu lệnh này để bạn có thể tiếp tục sử dụng cùng một ngôn ngữ trong khi sử dụng một ngày khác trong ngày đầu tuần.
Nhưng như đã đề cập, SET DATEFIRST
giá trị không ảnh hưởng đến DATEDIFF()
hàm số. DATEDIFF()
hàm luôn giả định rằng Chủ nhật là ngày đầu tiên trong tuần bất kể SET DATEFIRST
của bạn là gì giá trị.
Điều này có thể gây ra một số sự cố thú vị khi sử dụng DATEDIFF()
nếu bạn không biết nó hoạt động như thế nào.
Nếu bạn thấy mình trong tình huống này, hy vọng các ví dụ trên trang này có thể giúp ích.
Ví dụ 1 - Vấn đề
Đầu tiên, đây là một ví dụ về vấn đề thực tế. Lưu ý rằng chúng tôi có thể truy xuất SET DATEFIRST
giá trị bằng cách chọn @@DATEFIRST
.
DECLARE @startdate date ='2025-01-05', @enddate date ='2025-01-06'; ĐẶT NGÔN NGỮ us_english; CHỌN @@ DATEFIRST NHƯ 'ĐẶT Giá trị DATEFIRST', DATEDIFF (tuần, @startdate, @enddate) NHƯ 'us_english DATEDIFF () Kết quả'; ĐẶT NGÔN NGỮ Tiếng Anh; CHỌN @@ DATEFIRST NHƯ 'Đặt giá trị DATEFIRST', DATEDIFF (tuần, @startdate, @enddate) NHƯ 'Tiếng Anh DATEDIFF () Kết quả';
Kết quả:
+ ----------------------- + ---------------------- ---------- + | ĐẶT giá trị DATEFIRST | us_english DATEDIFF () Kết quả || ----------------------- + ------------------- ------------- || 7 | 0 | + ----------------------- + ----------------------- --------- ++ ----------------------- + --------------- -------------- + | ĐẶT giá trị DATEFIRST | DATEDIFF của Anh () Kết quả || ----------------------- + ------------------- ---------- || 1 | 0 | + ----------------------- + ----------------------- ------ +
Trong trường hợp này, ngày đầu tiên rơi vào Chủ nhật và ngày thứ hai rơi vào Thứ Hai. Do đó, bạn thường mong đợi DATEDIFF()
của Anh kết quả trả về 1
. Bạn sẽ mong đợi điều này vì ranh giới phần trong tuần bị vượt qua khi nó đi từ Chủ Nhật đến Thứ Hai (vì SET DATEFIRST
giá trị là 1
có nghĩa là “Thứ Hai” và Thứ Hai đánh dấu sự bắt đầu của một tuần mới).
Nhưng vì DATEDIFF()
bỏ qua SET DATEFIRST
của bạn giá trị và giả định rằng Chủ nhật là ngày bắt đầu của tuần, chúng tôi nhận được cùng một kết quả cho cả hai ngôn ngữ.
Để chắc chắn, tôi sẽ chạy lại truy vấn, nhưng lần này tôi sẽ đặt SET DATEFIRST
giá trị rõ ràng . Nói cách khác, thay vì đặt ngôn ngữ, tôi sẽ sử dụng SET DATEFIRST
tuyên bố:
DECLARE @startdate date ='2025-01-05', @enddate date ='2025-01-06'; SET DATEFIRST 7; SELECT @@ DATEFIRST AS 'SET DATEFIRST Value', DATEDIFF (tuần, @startdate, @enddate) AS 'us_english DATEDIFF () Result'; SET DATEFIRST 1; SELECT @@ DATEFIRST AS 'SET DATEFIRST Value', DATEDIFF (week, @startdate, @enddate) AS 'British DATEDIFF () Result';
Kết quả:
+ ----------------------- + ---------------------- ---------- + | ĐẶT giá trị DATEFIRST | us_english DATEDIFF () Kết quả || ----------------------- + ------------------- ------------- || 7 | 0 | + ----------------------- + ----------------------- --------- ++ ----------------------- + --------------- -------------- + | ĐẶT giá trị DATEFIRST | DATEDIFF của Anh () Kết quả || ----------------------- + ------------------- ---------- || 1 | 0 | + ----------------------- + ----------------------- ------ +
Cùng một kết quả, ngay cả khi bạn đặt SET DATEFIRST
một cách rõ ràng giá trị. Tuy nhiên, điều này không có gì ngạc nhiên - tôi sẽ ngạc nhiên nếu điều đó không trả về cùng một kết quả.
Ngoài ra, điều này chỉ xác nhận rằng DATEDIFF()
đang hoạt động chính xác như dự định.
Vì vậy, làm cách nào để chúng tôi thay đổi nó để DATEDIFF()
của chúng tôi kết quả tôn vinh SET DATEFIRST
của chúng tôi giá trị?
Giải pháp
Dưới đây là một giải pháp / cách giải quyết sẽ cho phép bạn đạt được kết quả như mong đợi. Điều này sẽ đảm bảo rằng SET DATEFIRST
của bạn cài đặt được tính vào DATEDIFF()
của bạn các kết quả.
Tất cả những gì bạn cần làm là trừ đi @@DATEFIRST
từ ngày nhập.
DECLARE @startdate date ='2025-01-05', @enddate date ='2025-01-06'; SET DATEFIRST 7; SELECT @@ DATEFIRST AS 'SET DATEFIRST Value', DATEDIFF (tuần, DATEADD (ngày , example @ sqldat.com @ DATEFIRST, @startdate), DATEADD (day, example @ sqldat.com @ DATEFIRST, @enddate)) AS 'us_english DATEDIFF () Result'; SET DATEFIRST 1; SELECT @@ DATEFIRST AS 'SET DATEFIRST Giá trị ', DATEDIFF (tuần, DATEADD (ngày, example @ sqldat.com @ DATEFIRST, @startdate), DATEADD (ngày, example @ sqldat.com @ DATEFIRST, @enddate)) NHƯ' Kết quả DATEDIFF () của Anh ';Kết quả:
+ ----------------------- + ---------------------- ---------- + | ĐẶT giá trị DATEFIRST | us_english DATEDIFF () Kết quả || ----------------------- + ------------------- ------------- || 7 | 0 | + ----------------------- + ----------------------- --------- ++ ----------------------- + --------------- -------------- + | ĐẶT giá trị DATEFIRST | DATEDIFF của Anh () Kết quả || ----------------------- + ------------------- ---------- || 1 | 1 | + ----------------------- + ----------------------- ------ +Điều này sử dụng
DATEADD()
chức năng để giảm số lượng ngày nhập@@DATEFIRST
(làSET DATEFIRST
của bạn giá trị).Trong trường hợp này,
DATEDIFF()
hàm vẫn sử dụng Chủ nhật là ngày đầu tiên của tuần, tuy nhiên, các ngày thực tế được sử dụng trong phép tính là khác nhau. Chúng đã được chuyển ngược thời gian theo số tiền@@DATEFIRST
.Ví dụ sau đây cho thấy các ngày được sử dụng trong phép tính:
DECLARE @startdate date ='2025-01-05', @enddate date ='2025-01-06'; SET DATEFIRST 7; SELECT @startdate AS 'Original Date', @@ DATEFIRST AS 'Subtract By', DATEADD (day, example @ sqldat.com @ DATEFIRST, @startdate) AS 'Ngày kết quả'UNION ALLSELECT @enddate, @@ DATEFIRST, DATEADD (day, example @ sqldat.com @ DATEFIRST, @enddate); ĐẶT DATEFIRST 1; CHỌN @startdate làm 'Ngày gốc', @@ DATEFIRST làm 'Trừ đi', DATEADD (ngày, ví dụ @ sqldat.com @ DATEFIRST, @startdate) Làm 'Ngày kết quả'UNION ALLSELECT @enddate, @@ DATEFIRST , DATEADD (ngày, ví dụ @ sqldat.com @ DATEFIRST, @enddate);Kết quả:
+ ----------------- + --------------- + ------------ ------ + | Ngày gốc | Trừ đi bằng | Ngày kết quả || ----------------- + --------------- + ------------ ------ || Năm 2025-01-05 | 7 | 2024-12-29 || Năm 2025-01-06 | 7 | 2024-12-30 | + ----------------- + --------------- + --------- --------- ++ ----------------- + --------------- + ----- ------------- + | Ngày gốc | Trừ đi bằng | Ngày kết quả || ----------------- + --------------- + ------------ ------ || Năm 2025-01-05 | 1 | Năm 2025-01-04 || Năm 2025-01-06 | 1 | 2025-01-05 | + ----------------- + --------------- + --------- --------- +Vì vậy, trong giải pháp của chúng tôi,
DATEDIFF()
đã sử dụng "Ngày kết quả" trong các tính toán của nó.Nếu bạn đang gặp sự cố với
DATEDIFF()
bỏ quaSET DATEFIRST
, hy vọng bài viết này hữu ích.