Cách tiếp cận tốt nhất để loại bỏ một phần thời gian của datetime trong SQL Server


514

Phương pháp nào cung cấp hiệu suất tốt nhất khi xóa phần thời gian khỏi trường datetime trong SQL Server?

a) select DATEADD(dd, DATEDIFF(dd, 0, getdate()), 0)

hoặc là

b) select cast(convert(char(11), getdate(), 113) as datetime)

Phương thức thứ hai cũng gửi thêm một vài byte nhưng điều đó có thể không quan trọng bằng tốc độ chuyển đổi.

Cả hai cũng có vẻ rất nhanh, nhưng có thể có sự khác biệt về tốc độ khi xử lý hàng trăm nghìn hoặc nhiều hàng hơn?

Ngoài ra, có thể có những phương pháp thậm chí tốt hơn để loại bỏ phần thời gian của một datetime trong SQL không?


1
Tôi đã thử điều này trên một triệu bản ghi trong một trong các bảng sản xuất của mình và tôi cũng không thể đọc được chính xác về hiệu suất. Cả hai phương pháp đều trả về cùng một lượng dữ liệu.
Stephen Perelson

9
Trên 18.000.000 hàng, đây là những gì tôi đã tìm thấy (SQL Server 2008): Phương pháp b chậm hơn khoảng 24% so với phương pháp a. CAST (FLOOR (CAST (getdate () AS FLOAT)) AS DATETIME) chậm hơn 3,5% so với phương pháp a. Phương pháp a dường như là một người chiến thắng liên quan đến hiệu suất. Cảm ơn tất cả các câu trả lời tuyệt vời.
Stephen Perelson

46
Tại sao SQL không có chức năng tích hợp sẵn để thực hiện việc này? !!
Gary McGill

10
Kiểu dữ liệu DATE mới của SQL 2008 sẽ xử lý việc này.
Philip Kelley

Câu trả lời:


558

Nghiêm túc, phương pháp alà ít tài nguyên nhất:

a) select DATEADD(dd, DATEDIFF(dd, 0, getdate()), 0)

Đã chứng minh ít CPU hơn với tổng thời lượng một triệu hàng bởi một số người có quá nhiều thời gian trong tay: Cách hiệu quả nhất trong SQL Server để lấy ngày từ ngày + giờ?

Tôi thấy một thử nghiệm tương tự ở nơi khác với kết quả tương tự quá.

Tôi thích DATEADD / DATEDIFF vì:

Chỉnh sửa, tháng 10 năm 2011

Đối với SQL Server 2008+, bạn có thể CAST datetức là CAST(getdate() AS date). Hoặc chỉ sử dụng datedatatype để không có thời gian để loại bỏ.

Chỉnh sửa, tháng 1 năm 2012

Một ví dụ hoạt động về mức độ linh hoạt của nó: Cần tính toán theo thời gian làm tròn hoặc số ngày trong máy chủ sql

Chỉnh sửa, tháng 5 năm 2012

Không sử dụng điều này trong các mệnh đề WHERE và tương tự mà không cần suy nghĩ: thêm chức năng hoặc CAST vào cột làm mất hiệu lực sử dụng chỉ mục. Xem số 2 tại đây: http://www.simple-talk.com/sql/t-sql-programming/ten-common-sql-programming-mistakes/

Bây giờ, điều này đã có một ví dụ về các phiên bản tối ưu hóa SQL Server sau này quản lý CAST chính xác, nhưng nói chung nó sẽ là một ý tưởng tồi ...

Chỉnh sửa, tháng 9 năm 2018, cho datetime2

DECLARE @datetime2value datetime2 = '02180912 11:45' --this is deliberately within datetime2, year 0218
DECLARE @datetime2epoch datetime2 = '19000101'

select DATEADD(dd, DATEDIFF(dd, @datetime2epoch, @datetime2value), @datetime2epoch)

3
@David Sopko cho lần chỉnh sửa tháng 10 năm 2011 thì mã sẽ là: chọn diễn viên (GETDATE () là ngày)
Choco Smith

1
Đối với các phiên bản SQL gần đây hơn, sử dụng ngày thay vì datetime sẽ tránh được yêu cầu xử lý hàng giờ. Sử dụng mẫu sau: khai báo noTime date = getdate (), withTime datetime = getdate () select @ noTime, @ withTime
ozkary

1
dàn diễn viên như ngày là tuyệt vời nếu bạn chỉ cần ngày. Tuy nhiên, thường thì bạn cần ngày hiện tại vào lúc nửa đêm để sau đó bạn có thể thực hiện một số thao tác ngày khác. các DATEdữ liệu thời gian là obnoxiously hạn chế vào những gì nó sẽ cho phép bạn làm có liên quan đến những thứ như dateadd, datediff và tương tác với ngày / giờ các kiểu dữ liệu khác với. Đối với những trường hợp, DATEADD()cách tiếp cận trị vì vua.
Xedni

Điều này không hoạt động cho mỗi ngày. Tôi đã nhập nhầm 0218thay vì 2018như năm và DATEDIFFmột phần trong tuyên bố của bạn đưa ra một ngoại lệ The conversion of a datetime2 data type to a datetime data type resulted in an out-of-range datetime valueHãy thử:select DATEDIFF(dd, 0, convert(datetime2(0), '0218-09-12', 120))
Bernhard Döbler

1
@ BernhardDöbler vào tháng 7 năm 2009 khi tôi trả lời, "0218" sẽ là một ngày hợp lệ vì vậy bạn sẽ không có được điều này đến nay. Ngoài ra, "0" không chuyển đổi thành 19000101 cho datetime2. Hãy thử chọn nàySELECT DATEDIFF(dd, '19000101', convert(datetime2(0), '0218-09-12', 120))
gbn

69

Trong SQL Server 2008, bạn có thể sử dụng:

CONVERT(DATE, getdate(), 101)

13
Đối số thứ ba hoàn toàn không ảnh hưởng đến kết quả khi chuyển đổi từ a datetimesang a date, và do đó, giải pháp của bạn thực sự sôi sục thành chỉ CONVERT(DATE,getdate()), điều đã được đề xuất nhiều lần.
Andriy M

Chỉ cần sử dụng CAST(GETDATE() AS DATE)hoặc nghiêm ngặt ANSI CAST(CURRENT_TIMESTAMP AS DATE)mà tôi nghĩ là vô giá trị. Ở lại với người đầu tiên.
Ivanzinho

52

Tất nhiên đây là một chủ đề cũ nhưng để làm cho nó hoàn thành.

Từ SQL 2008, bạn có thể sử dụng kiểu dữ liệu DATE để bạn có thể thực hiện đơn giản:

SELECT CONVERT(DATE,GETDATE())

21
SELECT CAST(FLOOR(CAST(getdate() AS FLOAT)) AS DATETIME)

... không phải là một giải pháp tốt, theo các ý kiến ​​dưới đây.

Tôi sẽ xóa câu trả lời này, nhưng tôi sẽ để nó ở đây làm ví dụ vì tôi nghĩ rằng lời giải thích của các nhà bình luận về lý do tại sao nó không phải là một ý tưởng tốt vẫn hữu ích.


Xem câu trả lời của GBN, nhiều người đã điều tra việc này. Các dữ liệu KHÔNG được lưu trữ dưới dạng phao và do đó, sử dụng DATEADD / DATEDIFF để tránh các thao tác toán học cần phải CAST giữa các loại.
MatBailie

Tôi có thể chấp nhận rằng bạn có thể muốn tránh truyền từ DATETIME sang FLOAT vì lý do bạn mô tả, nhưng trong trường hợp đó không phải là chuyển đổi ngầm định từ số 0 trong tùy chọn OP (a) cũng là một vấn đề? Hmmm ... Tôi cho rằng trong trường hợp đó không phải là FLOAT và máy chủ có lẽ đủ thông minh để loại bỏ thông tin thời gian. OK, tôi thừa nhận :-)
Gary McGill

Số 0 thực sự là một chuyển đổi ngầm định từ một loại số (INT tôi đoán) sang một dữ liệu. Tuy nhiên, vì đó là biểu thức không đổi, trình tối ưu hóa có thể thực hiện điều đó tại thời gian biên dịch cho các thủ tục được lưu trữ và chỉ cần thực hiện một lần để thực thi SQL một cách linh hoạt. Nói tóm lại, có một chi phí một lần cho điều đó, truy vấn dựa trên FLOAT có chi phí tương đương cho mỗi Hàng.
MatBailie

Đúc để nổi là không chính xác khủng khiếp. Câu trả lời này nên được xóa. Không ai nên sử dụng mã này.
usr

3
Chưa kể rằng không an toàn khi chuyển sang float và quay lại datetime - float không có đủ độ chính xác. Vì vậy, tôi nghĩ rằng nó không thể được khuyến khích ở tất cả. Xem bài này để biết thêm chi tiết .
ErikE

17

Trong SQL Server 2008, có một kiểu dữ liệu DATE (cũng là kiểu dữ liệu TIME).

CAST(GetDate() as DATE)

hoặc là

declare @Dt as DATE = GetDate()

Đây là những gì tôi đã sử dụng và nó hoạt động tốt. Có vẻ như câu trả lời đơn giản nhất. Bất kỳ nhược điểm nào khi sử dụng kết hợp w / CHUYỂN ĐỔI?
joelmdev

1
CAST và CONVERT tương đương về chức năng. Sự khác biệt là CAST là một phần của tiêu chuẩn ANSI, trong khi CONVERT dành riêng cho T-SQL. Vì vậy, sử dụng CAST bất cứ nơi nào có thể.
troy

@troy Tôi sử dụng CAST vì tôi có thể lưu 3 chữ cái gõ và cú pháp rõ ràng hơn CONVERT, phần ANSI Standard không có giá trị
Ivanzinho

8

Đây là một câu trả lời khác, từ một câu hỏi trùng lặp khác :

SELECT CAST(CAST(getutcdate() - 0.50000004 AS int) AS datetime) 

Phương pháp số ma thuật này thực hiện nhanh hơn một chút so với phương pháp DATEADD. (Có vẻ như ~ 10%)

Thời gian CPU trên một số vòng của một triệu bản ghi:

DATEADD   MAGIC FLOAT
500       453
453       360
375       375
406       360

Nhưng lưu ý rằng những con số này có thể không liên quan vì chúng đã RẤT nhanh. Trừ khi tôi có bộ kỷ lục từ 100.000 trở lên, tôi thậm chí không thể có được Thời gian CPU để đọc trên 0.

Xem xét thực tế rằng DateAdd có nghĩa cho mục đích này và mạnh mẽ hơn, tôi nói rằng hãy sử dụng DateAdd.


1
Điều đó thật kinh khủng. Tôi sẽ không bao giờ đặt dữ liệu của mình vào rủi ro như thế này. Ai biết nếu điều này là chính xác cho tất cả các thời gian, không chỉ những người bạn đã thử nghiệm.
usr

@usr Ồ, đúng rồi, nó chỉ là một con số kỳ diệu và không nên được sử dụng vì lý do đó. Nếu bạn muốn kiểm tra tính chính xác của nó, chỉ cần nhét tất cả các ngày có thể trong một ngày vào bảng và kiểm tra kết quả! Cũng xem bài viết này để biết thêm thông tin.
ErikE

@ErikE điểm tốt. Câu trả lời của bạn cung cấp khả năng sử dụng '12:00:00.003'mà tôi nghĩ là tốt hơn nhiều, mặc dù.
usr

6
SELECT CAST(CAST(GETDATE() AS DATE) AS DATETIME)

4
Một lựa chọn hợp lệ, có. Đề xuất nhiều hơn một lần trong chủ đề này, mặc dù.
Andriy M

Thành thật mà nói, giải pháp này là dễ đọc nhất. Goto của tôi
BelgoCanadian

5

Tôi thật sự thích:

[date] = CONVERT(VARCHAR(10), GETDATE(), 120)

Các 120mã định dạng sẽ ép buộc ngày vào tiêu chuẩn ISO 8601:

'YYYY-MM-DD' or '2017-01-09'

Siêu dễ sử dụng trong dplyr ( R) và gấu trúc ( Python)!


3

HÃY THỬ!

Phương pháp a) và b) KHÔNG phải luôn có cùng một đầu ra!

select DATEADD(dd, DATEDIFF(dd, 0, '2013-12-31 23:59:59.999'), 0)

Đầu ra: 2014-01-01 00:00:00.000

select cast(convert(char(11), '2013-12-31 23:59:59.999', 113) as datetime)

Đầu ra: 2013-12-31 00:00:00.000

(Đã thử nghiệm trên MS SQL Server 2005 và 2008 R2)

EDIT: Theo nhận xét của Adam, điều này không thể xảy ra nếu bạn đọc giá trị ngày từ bảng, nhưng nó có thể xảy ra nếu bạn cung cấp giá trị ngày của bạn dưới dạng chữ (ví dụ: như một tham số của thủ tục được lưu trữ được gọi qua ADO.NET).


1
.999 không thể được lưu trữ trong SQL Server trong một DATETIMEcột. Mức cao nhất hiện có là 0,997 Từ: msdn.microsoft.com/en-us/l Library / ms187819.aspx bạn sẽ thấy rằng các giá trị được làm tròn để có vị trí thứ một đến 0, 3 hoặc 7. OP sẽ không nhìn thấy giá trị từ bài kiểm tra của bạn trong bảng của họ.
Adam Wenger

Bạn nói đúng. Tôi không có ý định đăng bài này như một câu trả lời cho câu hỏi của OP, nhưng như một bình luận cho người khác xem, nhưng tôi chỉ có 11 điểm danh tiếng và 15 điểm cần thiết để bình luận.
broslav

Trong đoạn mã đầu tiên của bạn, hằng số chuỗi được chuyển đổi hoàn toàn thành datetime, trong đoạn thứ hai của bạn, nó vẫn là một chuỗi (và 113 chỉ bị bỏ qua).
Andriy M

2

Dải thời gian trên chèn / cập nhật ở vị trí đầu tiên. Đối với chuyển đổi nhanh chóng, không có gì có thể đánh bại chức năng bảo trì chức năng do người dùng xác định:

select date_only(dd)

Việc triển khai date_onlycó thể là bất cứ điều gì bạn thích - bây giờ nó được trừu tượng hóa và gọi mã sạch hơn nhiều.


Tôi đã từng nghĩ ra một kích hoạt để chà thời gian từ các cột được chọn. Nếu dữ liệu không thể xấu, bạn không cần phải xóa dữ liệu.
Philip Kelley

2
Có một nhược điểm của phương pháp UDF, chúng không phải là SARGable. Nếu được sử dụng trong các mệnh đề THAM GIA hoặc WHERE, trình tối ưu hóa không thể sử dụng INDEX để cải thiện hiệu suất. Tuy nhiên, sử dụng phương pháp DATEADD / DATEDIFF là SARGable và sẽ có thể hưởng lợi từ INDEX. (Rõ ràng phương pháp FLOAT cũng là SARGable)
MatBailie

1
@MatBailie Tôi xin khác! Các UDF chắc chắn không phải là SARGable, nhưng Dateadd cũng không phải là Convert để nổi! WHERE DateAdd(DateDiff(Column)) = @DateValuesẽ không sử dụng một chỉ mục. Mặt khác, WHERE Column >= dbo.UDF(@DateValue) AND Column < dbo.UDF(@DateValue + 1) SARGable. Vì vậy, hãy cẩn thận làm thế nào bạn đặt nó.
ErikE

2

Xem câu hỏi này:
Làm cách nào tôi có thể cắt một datetime trong SQL Server?

Dù bạn làm gì, đừng sử dụng phương thức chuỗi . Đó là về cách tồi tệ nhất bạn có thể làm điều đó.


Cảm ơn, tôi đoán điều này đã được hỏi trước đây. Điều kỳ lạ là các thí nghiệm của tôi đã chỉ ra rằng phương thức float thực sự chậm hơn 3,5% trên SQL Server 2008 so với phương thức dateadd (dd, 0, dateiff (dd, 0, getDate ())). Tôi đã chạy thử nghiệm nhiều lần cho mỗi phương thức và máy chủ cơ sở dữ liệu không được sử dụng cho bất kỳ điều gì khác vào thời điểm đó.
Stephen Perelson

Chúng ta hãy nói rằng tôi nghi ngờ về điểm chuẩn được thực hiện bởi bất kỳ ai không chứng minh rằng họ thực hiện điểm chuẩn thường xuyên và theo cách rất khoa học như một phần công việc của họ. Ngay cả điểm chuẩn của Thomas trong liên kết của gbn cũng có một số vấn đề rõ ràng khi bạn nhìn vào nó. Điều đó không làm cho nó sai nhất thiết, chỉ là không dứt khoát. Phương pháp đúc / sàn / diễn viên là cách nhanh nhất được chấp nhận trong một thời gian rất dài và tôi nghi ngờ nó đã từng là sự thật không thể chối cãi. Điều đó nói rằng, tôi đang bắt đầu xem xét lại nó; đặc biệt là cho máy chủ sql 2008, dù sao nó hoàn toàn không cần thiết.
Joel Coehoorn

1
Phương thức chuỗi cực kỳ dễ sử dụng, để đọc và ghi nhớ. Đó là những yếu tố rất quan trọng mà tôi nghĩ rằng bạn đang đánh giá thấp!
Ben

1
@JoelCoehoorn, chuyển đổi kiểu 121 được gọi là "ODBC Canonical". Nó không thay đổi với đối chiếu hoặc miền địa phương. Thủ thuật chuỗi cũng dễ dàng khái quát theo năm, năm + tháng, ngày, giờ hoặc phút.
Ben

1
@Ben Thủ thuật chuỗi dạy cho các nhà phát triển sử dụng chuyển đổi chuỗi. Chúng hoạt động , nhưng toán học ngày tháng rất xa, vượt trội hơn rất nhiều, vì nhiều lý do, không phải ít nhất là tốc độ - mà thậm chí nhiều hơn, đối với việc học làm việc với những con số ngày tháng liên quan đến nhà phát triển và khả năng tinh thần của anh ấy được chất lỏng với thao tác số trong mã.
ErikE

2

Đã trả lời nhưng tôi cũng ném nó ra ngoài ... điều này chắc chắn cũng có hiệu quả tốt nhưng nó hoạt động bằng cách vứt bỏ số thập phân (lưu trữ thời gian) từ phao và chỉ trả lại toàn bộ phần (đó là ngày)

 CAST(
FLOOR( CAST( GETDATE() AS FLOAT ) )
AS DATETIME
)

Lần thứ hai tôi tìm thấy giải pháp này ... tôi đã lấy mã này ra


1
Chuyển đổi sang float là không an toàn .
ErikE

2
CAST(round(cast(getdate()as real),0,1) AS datetime)

Phương pháp này không sử dụng hàm chuỗi. Datevề cơ bản là một kiểu dữ liệu thực với các chữ số trước số thập phân là một phần của một ngày.

Điều này tôi đoán sẽ nhanh hơn rất nhiều.


1
Đúc như phao không an toàn .
ErikE


2

chọn CHUYỂN ĐỔI (char (10), GetDate (), 126)


Sự khác biệt chính của đề xuất của bạn với phương pháp được đề cập trong câu trả lời của @ broslav hoặc từ phương pháp được xác định là chậm nhất trong chuỗi này (cùng liên kết như trong câu trả lời được chấp nhận) là gì?
Andriy M

1

Tôi nghĩ bạn muốn nói cast(floor(cast(getdate()as float))as datetime)

thực chỉ là 32 bit và có thể mất một số thông tin

Đây là nhanh nhất cast(cast(getdate()+x-0.5 as int)as datetime)

... mặc dù chỉ nhanh hơn khoảng 10%(about 0.49 microseconds CPU vs. 0.58)

Điều này đã được đề xuất và mất cùng thời gian trong thử nghiệm của tôi ngay bây giờ: DATEADD(dd, DATEDIFF(dd, 0, getdate()), 0)

Trong SQL 2008, hàm SQL CLR nhanh hơn khoảng 5 lần so với sử dụng hàm SQL, ở mức 1,35 micro giây so với 6,5, cho thấy chi phí gọi hàm thấp hơn nhiều cho hàm SQL CLR so với SQL UDF đơn giản.

Trong SQL 2005, hàm SQL CLR nhanh hơn 16 lần, theo thử nghiệm của tôi, so với hàm chậm này:

create function dateonly (  @dt datetime )
returns datetime
as
begin
return cast(floor(cast(@dt as float))as int)
end

1

Thế còn select cast(cast my_datetime_field as date) as datetime)? Điều này dẫn đến cùng một ngày, với thời gian được đặt thành 00:00, nhưng tránh mọi chuyển đổi thành văn bản và cũng tránh mọi làm tròn số rõ ràng.



Chúng không giống nhau. Các câu trả lời khác đề nghị bỏ nó vào một ngày không có thành phần thời gian và để nó như thế. Bài đăng của tôi đặt nó thành một datetime với thời gian lúc nửa đêm. Đây là sự khác biệt lớn; hãy thử xuất sang MS Excel và bạn sẽ thấy rằng nó xử lý thời gian tốt hơn nhiều so với ngày.
Tiến sĩ đã

Cái đầu tiên giống hệt nhau.
Mikael Eriksson

Ok, vâng, tôi thấy cái đó bây giờ. Tôi sẽ rất vui khi loại bỏ câu trả lời của mình dưới dạng trùng lặp, nếu cần thiết.
Tiến sĩ Drew

1

Tôi nghĩ rằng nếu bạn kiên quyết với TSQLđiều đó thì đây là cách nhanh nhất để rút ngắn thời gian:

 select convert(datetime,convert(int,convert(float,[Modified])))

Tôi thấy phương pháp cắt này nhanh hơn khoảng 5% so với DateAddphương pháp. Và điều này có thể dễ dàng sửa đổi để làm tròn đến ngày gần nhất như thế này:

select convert(datetime,ROUND(convert(float,[Modified]),0))

Chuyển đổi sang float là không an toàn .
ErikE

1

Ở đây tôi đã thực hiện một chức năng để loại bỏ một số phần của datetime cho SQL Server. Sử dụng:

  • Param đầu tiên là datetime được loại bỏ.
  • Thông số thứ hai là một char:
    • s: làm tròn đến giây; loại bỏ mili giây
    • m: làm tròn đến phút; loại bỏ giây và mili giây
    • h: vòng đến giờ; loại bỏ phút, giây và mili giây.
    • d: vòng đến ngày; loại bỏ giờ, phút, giây và mili giây.
  • Trả về datetime mới

create function dbo.uf_RoundDateTime(@dt as datetime, @part as char) returns datetime as begin if CHARINDEX( @part, 'smhd',0) = 0 return @dt; return cast( Case @part when 's' then convert(varchar(19), @dt, 126) when 'm' then convert(varchar(17), @dt, 126) + '00' when 'h' then convert(varchar(14), @dt, 126) + '00:00' when 'd' then convert(varchar(14), @dt, 112) end as datetime ) end


Cảm ơn Andriy! Tôi không biết đề xuất của tôi không hiệu quả. Ít nhất là nó hoạt động, nhưng bạn đã đúng.
Max Vargas

1

Chỉ trong trường hợp bất cứ ai đang tìm kiếm một phiên bản Sybase ở đây vì một số phiên bản ở trên không hoạt động

CAST(CONVERT(DATE,GETDATE(),103) AS DATETIME)
  • Đã thử nghiệm trong I SQL v11 chạy trên Máy chủ thích ứng 15.7

Điều này phù hợp hơn khi chỉnh sửa câu trả lời được chấp nhận. Với 20 câu trả lời khác, điều này sẽ bị chôn vùi và không thể thực hiện được. Ngoài ra, câu trả lời được chấp nhận đề cập đến việc sử dụng cast: Đối với SQL Server 2008+, bạn có thể CAST cho đến nay. Hoặc chỉ sử dụng ngày để không có thời gian để loại bỏ.
EWit

Tốt nhất nên đăng bài này dưới dạng câu trả lời cho câu hỏi Sybase tương đương. Nếu không có câu hỏi nào như vậy, bạn có thể tự do tạo một câu hỏi (và tự trả lời).
Andriy M

Ngoài ra, việc chỉ định tham số thứ ba thành CHUYỂN ĐỔI là vô nghĩa khi bạn chuyển đổi datetimethành date: không ai trong số đó có định dạng vốn có.
Andriy M

0

Nếu có thể, đối với những thứ đặc biệt như thế này, tôi thích sử dụng các hàm CLR.

Trong trường hợp này:

[Microsoft.SqlServer.Server.SqlFunction]
    public static SqlDateTime DateOnly(SqlDateTime input)
    {
        if (!input.IsNull)
        {
            SqlDateTime dt = new SqlDateTime(input.Value.Year, input.Value.Month, input.Value.Day, 0, 0, 0);

            return dt;
        }
        else
            return SqlDateTime.Null;
    }

0

Tôi, cá nhân, hầu như luôn luôn sử dụng các chức năng do Người dùng Xác định do cho việc này nếu xử lý SQL Server 2005 (hoặc phiên bản thấp hơn), tuy nhiên, cần lưu ý rằng có những hạn chế cụ thể khi sử dụng UDF, đặc biệt là nếu áp dụng chúng cho các mệnh đề WHERE (xem bên dưới và các ý kiến ​​về câu trả lời này để biết thêm chi tiết). Nếu sử dụng SQL Server 2008 (hoặc cao hơn) - xem bên dưới.

Trên thực tế, đối với hầu hết các cơ sở dữ liệu mà tôi tạo, tôi thêm các UDF này ngay khi bắt đầu vì tôi biết có khả năng 99% tôi sẽ cần chúng sớm hay muộn.

Tôi tạo một cái cho "chỉ ngày" và "chỉ thời gian" (mặc dù cái "chỉ ngày" là thứ được sử dụng nhiều nhất trong hai cái).

Đây là một số liên kết đến một loạt các UDF liên quan đến ngày:

Essential SQL Server Ngày, Thời gian và DateTime Chức năng
Nhận Ngày Chỉ Chức năng

Liên kết cuối cùng đó hiển thị không dưới 3 cách khác nhau để lấy ngày chỉ là một phần của trường thời gian và đề cập đến một số ưu và nhược điểm của mỗi phương pháp.

Nếu sử dụng UDF, cần lưu ý rằng bạn nên cố gắng tránh sử dụng UDF như một phần của mệnh đề WHERE trong truy vấn vì điều này sẽ cản trở rất nhiều hiệu năng của truy vấn. Lý do chính cho điều này là việc sử dụng UDF trong mệnh đề WHERE biểu thị mệnh đề đó là không thể sargable , điều đó có nghĩa là SQL Server không còn có thể sử dụng một chỉ mục với mệnh đề đó để cải thiện tốc độ thực hiện truy vấn. Với tham chiếu đến việc sử dụng UDF của riêng tôi, tôi sẽ thường xuyên sử dụng cột ngày "thô" trong mệnh đề WHERE, nhưng áp dụng UDF cho cột CHỌN. Theo cách này, UDF chỉ được áp dụng cho tập kết quả được lọc và không phải mọi hàng của bảng là một phần của bộ lọc.

Tất nhiên, cách tiếp cận tốt nhất tuyệt đối cho việc này là sử dụng SQL Server 2008 (hoặc cao hơn) và tách biệt ngày và giờ của bạn , vì công cụ cơ sở dữ liệu SQL Server sau đó sẽ cung cấp các thành phần ngày và giờ riêng lẻ và có thể truy vấn một cách độc lập không cần UDF hoặc cơ chế khác để trích xuất phần ngày hoặc thời gian từ loại thời gian tổng hợp.


Sử dụng UDF có thể tốt trong một số trường hợp (như khi chà các tham số). Nhưng trong hầu hết các tình huống, đó là một giải pháp khủng khiếp - chạy UDF một lần cho mỗi hàng là một cách để giết hiệu năng của truy vấn mà không cần bất kỳ yêu cầu nào!
ErikE

@ErikE - Tôi không đồng ý, Erik, UDF là những kẻ giết hiệu suất, đó là lý do tại sao tôi nói rằng, nếu bạn có thể sử dụng SQL Server 2008 trở lên và sử dụng kiểu dữ liệu tích hợp sẵn cho bạn, đó sẽ là giải pháp tốt nhất (cả về mặt đạt được những gì cần thiết và về hiệu suất). Nếu bạn bị mắc kẹt với phiên bản SQL Server cũ hơn không hỗ trợ điều này, bạn sẽ từ bỏ thứ gì đó để đạt được yêu cầu của mình.
CraigTP

Thật. Sẽ thật tuyệt nếu công cụ cơ sở dữ liệu cung cấp cho chúng tôi thứ gì đó là SARGable, nhưng dễ thể hiện hơn. Trong khi đó, nếu bạn đang tìm kiếm một giá trị bất cứ lúc nào trong cả ngày, thì đây vẫn là giải pháp tốt nhất (đối với ít nhất là các phiên bản SQL cũ hơn) : WHERE DateColumn >= {TimeTruncatingExpression}(@DateValue) AND DateColumn < {TimeTruncatingExpression}(@DateValue + 1). Tôi cảm thấy như mình phải nói điều gì đó vì bạn nói "Tôi hầu như luôn sử dụng UDF" không giải thích bất kỳ nhược điểm nào, cũng như cách tạo truy vấn SARGable chỉ có ngày.
ErikE

@ErikE - Đừng lo lắng, Erik. Khi tôi đã sử dụng UDF, tôi đã làm việc với các tập dữ liệu nhỏ trong đó hiệu suất không phải là tối quan trọng, hoặc nhiều khả năng tôi đã lọc truy vấn theo trường ngày "thô" (để đảm bảo tính khả dụng) nhưng chọn cột với UDF được áp dụng. Vì đây thường là các bộ dữ liệu nhỏ sau khi được lọc, việc chạy UDF qua số lượng nhỏ các bản ghi này không phải là một điểm nhấn hiệu năng. Điều đó nói rằng, bạn nêu lên một điểm rất tốt và tôi đã cập nhật câu trả lời của mình để phản ánh điều này.
CraigTP

-4

Tôi sẽ dùng:

CAST
(
CAST(YEAR(DATEFIELD) as varchar(4)) + '/' CAST(MM(DATEFIELD) as varchar(2)) + '/' CAST(DD(DATEFIELD) as varchar(2)) as datetime
) 

Do đó, có hiệu quả tạo ra một trường mới từ trường ngày bạn đã có.


2
Tại sao bạn lại làm vậy? Bạn có nghĩ rằng trích xuất các bit từ một datetimegiá trị, chuyển đổi chúng thành các chuỗi, nối các chuỗi đó lại với nhau và cuối cùng chuyển đổi kết quả trở lại datetimetốt hơn là thực hiện các phép tính trực tiếp trên bản gốc datetime( phương thức DATEADD/ DATEDIFF) không?
Andriy M

Ngoài ra, những gì MMDD? Không có chức năng như vậy trong SQL Server.
Andriy M
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.