Pendekatan terbaik untuk menghapus bagian waktu datetime dalam SQL Server

514

Metode mana yang memberikan kinerja terbaik saat menghapus bagian waktu dari bidang datetime di SQL Server?

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

atau

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

Metode kedua memang mengirim beberapa byte lagi, tetapi itu mungkin tidak sepenting kecepatan konversi.

Keduanya juga tampak sangat cepat, tetapi mungkin ada perbedaan dalam kecepatan ketika berhadapan dengan ratusan ribu atau lebih baris?

Juga, mungkinkah ada metode yang lebih baik untuk menghilangkan bagian waktu datetime dalam SQL?

Stephen Perelson
sumber
1
Saya sudah mencoba ini pada satu juta rekaman di salah satu tabel produksi saya dan saya tidak bisa mendapatkan pembacaan yang akurat tentang kinerja. Kedua metode mengembalikan jumlah data yang sama persis.
Stephen Perelson
9
Pada baris 18.000.000 inilah yang saya temukan (SQL Server 2008): Metode b sekitar 24% lebih lambat daripada metode a. CAST (FLOOR (CAST (getdate () AS FLOAT)) AS DATETIME) lebih lambat 3,5% dari metode a. Metode a tampaknya menjadi pemenang dalam hal kinerja. Terima kasih atas jawaban yang bagus.
Stephen Perelson
46
Kenapa sih SQL tidak memiliki fungsi built-in untuk melakukan ini? !!
Gary McGill
10
DATE datatype baru SQL 2008 akan menangani ini.
Philip Kelley

Jawaban:

558

Secara ketat, metode aadalah sumber daya yang paling sedikit:

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

Terbukti kurang intensif CPU untuk durasi total yang sama satu juta baris oleh seseorang dengan terlalu banyak waktu di tangan mereka: Cara paling efisien dalam SQL Server untuk mendapatkan tanggal dari tanggal + waktu?

Saya melihat tes serupa di tempat lain dengan hasil yang sama juga.

Saya lebih suka DATEADD / DATEIFF karena:

Edit, Okt 2011

Untuk SQL Server 2008+, Anda dapat CAST untuk dateyaitu CAST(getdate() AS date). Atau cukup gunakan datetipe data sehingga tidak ada waktu untuk menghapus.

Edit, Jan 2012

Sebuah contoh yang dikerjakan tentang seberapa fleksibelnya ini: Perlu untuk menghitung dengan waktu bulat atau angka tanggal di sql server

Edit, Mei 2012

Jangan gunakan ini di klausa WHERE dan sejenisnya tanpa berpikir: menambahkan fungsi atau CAST ke kolom membatalkan penggunaan indeks. Lihat nomor 2 di sini: http://www.simple-talk.com/sql/t-sql-programming/ten-common-sql-programming-mistakes/

Sekarang, ini memang memiliki contoh versi pengoptimal SQL Server yang mengelola CAST hingga saat ini dengan benar, tetapi umumnya itu akan menjadi ide yang buruk ...

Edit, Sep 2018, untuk 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)
gbn
sumber
3
@ David Sopko untuk edit Oktober 2011 lalu kode akan menjadi: pilih pemeran (GETDATE () sebagai tanggal)
Choco Smith
1
Untuk versi SQL yang lebih baru, menggunakan tanggal sebagai ganti datetime menghindari perlunya berurusan dengan jam. Gunakan contoh berikut: nyatakan noTime date = getdate (), withTime datetime = getdate () pilih @ noTime, @ withTime
ozkary
1
para pemeran sebagai kencan itu hebat jika Anda hanya perlu kencan. Namun seringkali Anda memerlukan tanggal saat ini di tengah malam sehingga Anda dapat melakukan manipulasi tanggal lebih lanjut. yang DATEwaktu data menjengkelkan terbatas pada apa yang akan membiarkan Anda melakukan berkaitan dengan hal-hal seperti dateadd, datediff dan berinteraksi dengan tipe data tanggal / waktu lainnya. Untuk kasus-kasus itu, DATEADD()pendekatan itu memerintah raja.
Xedni
Ini tidak berfungsi untuk setiap tanggal. Saya keliru memasukkan 0218bukan 2018sebagai tahun dan DATEDIFFbagian dari pernyataan Anda melempar pengecualian The conversion of a datetime2 data type to a datetime data type resulted in an out-of-range datetime valueCoba:select DATEDIFF(dd, 0, convert(datetime2(0), '0218-09-12', 120))
Bernhard Döbler
1
@ BernhardDöbler pada Juli 2009 ketika saya menjawab, "0218" akan menjadi tanggal yang valid sehingga Anda tidak akan sejauh ini. Juga "0" tidak dikonversi ke 19000101 untuk datetime2. Coba pilih iniSELECT DATEDIFF(dd, '19000101', convert(datetime2(0), '0218-09-12', 120))
gbn
69

Di SQL Server 2008, Anda dapat menggunakan:

CONVERT(DATE, getdate(), 101)
Anto Raja Prakash
sumber
13
Argumen ketiga sama sekali tidak ada kaitannya dengan hasil ketika mengkonversi dari a datetimeke date, dan solusi Anda secara efektif bermuara pada just CONVERT(DATE,getdate()), yang telah disarankan lebih dari sekali.
Andriy M
Cukup gunakan CAST(GETDATE() AS DATE)atau ANSI ketat CAST(CURRENT_TIMESTAMP AS DATE)yang saya pikir tidak berharga. Tetap dengan yang pertama.
Ivanzinho
52

Tentu saja ini adalah utas lama tetapi untuk membuatnya lengkap.

Dari SQL 2008 Anda dapat menggunakan DATE datatype sehingga Anda dapat melakukannya:

SELECT CONVERT(DATE,GETDATE())
Arjan Fraaij
sumber
21
SELECT CAST(FLOOR(CAST(getdate() AS FLOAT)) AS DATETIME)

... bukan solusi yang baik, sesuai komentar di bawah.

Saya akan menghapus jawaban ini, tetapi saya akan meninggalkannya di sini sebagai contoh tandingan karena saya pikir penjelasan komentator tentang mengapa itu bukan ide yang baik masih berguna.

Gary McGill
sumber
Lihat jawaban GBN, banyak yang telah menyelidiki ini. DATETIME TIDAK disimpan sebagai pelampung, dan karenanya menggunakan DATEADD / DATEDIFF menghindari kebutuhan manipulasi matematis untuk melakukan CAST antar tipe.
MatBailie
Saya dapat menerima bahwa Anda mungkin ingin menghindari para pemeran dari DATETIME ke FLOAT karena alasan yang Anda jelaskan, tetapi dalam hal ini bukankah konversi implisit dari nol pada opsi OPs (a) juga merupakan masalah? Hmmm ... Saya kira dalam kasus itu bukan FLOAT dan bahwa server mungkin cukup pintar untuk membuang info waktu. OK, saya mengakui :-)
Gary McGill
0 memang merupakan konversi implisit dari tipe numerik (INT, saya kira) menjadi DATETIME. Karena ini adalah ekspresi yang konstan, pengoptimal dapat melakukannya pada waktu kompilasi untuk Prosedur Tersimpan dan hanya perlu melakukannya sekali untuk menjalankan SQL secara dinamis. Singkatnya, ada satu kali overhead untuk itu, permintaan berbasis FLOAT memiliki overhead yang sama untuk setiap Baris.
MatBailie
Casting untuk mengapung sangat tidak aman. Jawaban ini harus dihapus. Tidak ada yang harus menggunakan kode ini.
usr
3
Belum lagi itu tidak aman untuk dilemparkan ke float dan kembali ke datetime - float tidak memiliki cukup presisi. Karena itu saya pikir itu tidak dapat direkomendasikan sama sekali. Lihat posting ini untuk detail lebih lanjut .
ErikE
17

Dalam SQL Server 2008, ada tipe data DATE (juga tipe data TIME).

CAST(GetDate() as DATE)

atau

declare @Dt as DATE = GetDate()
Metafora
sumber
Inilah yang saya gunakan dan itu bekerja dengan baik. Sepertinya jawaban yang paling sederhana. Adakah kerugian penggunaannya bersamaan dengan CONVERT?
joelmdev
1
CAST dan CONVERT memiliki fungsi yang setara. Perbedaannya adalah bahwa CAST adalah bagian dari standar ANSI, sementara CONVERT khusus untuk T-SQL. Jadi, gunakan CAST sedapat mungkin.
troy
@troy Saya menggunakan CAST karena saya dapat menyimpan 3 mengetik huruf dan sintaksinya lebih jelas daripada CONVERT, bagian ANSI Standard tidak berharga
Ivanzinho
8

Ini jawaban lain, dari pertanyaan rangkap lain :

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

Metode angka ajaib ini melakukan sedikit lebih cepat daripada metode DATEADD. (Sepertinya ~ 10%)

Waktu CPU pada beberapa putaran satu juta catatan:

DATEADD   MAGIC FLOAT
500       453
453       360
375       375
406       360

Tetapi perhatikan bahwa angka-angka ini mungkin tidak relevan karena mereka sudah SANGAT cepat. Kecuali jika saya memiliki rekor 100.000 atau lebih, saya bahkan tidak bisa mendapatkan Waktu CPU untuk membaca di atas nol.

Mengingat fakta bahwa DateAdd dimaksudkan untuk tujuan ini dan lebih kuat, saya akan mengatakan menggunakan DateAdd.

Jeff Meatball Yang
sumber
1
Itu mengerikan. Saya tidak pernah menempatkan data saya dalam risiko seperti ini. Siapa yang tahu apakah ini benar untuk semua data , bukan hanya yang Anda uji.
usr
@ Usr Oh, benar, ini hanya angka ajaib dan tidak boleh digunakan untuk alasan itu. Jika Anda ingin memeriksa kebenarannya, cukup isi semua tanggal yang mungkin untuk satu hari dalam satu tabel dan periksa hasilnya! Lihat juga posting ini untuk informasi lebih lanjut.
ErikE
@ErikE poin bagus. Jawaban Anda memberikan kemungkinan menggunakan '12:00:00.003'yang menurut saya jauh lebih baik.
usr
6
SELECT CAST(CAST(GETDATE() AS DATE) AS DATETIME)
Byju
sumber
4
Opsi yang valid, ya. Disarankan lebih dari sekali di utas ini.
Andriy M
Jujur, solusi ini paling mudah dibaca. Goto saya
BelgoCanadian
5

Saya sangat suka:

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

The 120Kode Format akan memaksa tanggal ke dalam ISO 8601 standar:

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

Sangat mudah digunakan di dplyr ( R) dan panda ( Python)!

emehex
sumber
3

WASPADALAH!

Metode a) dan b) TIDAK selalu memiliki output yang sama!

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

Keluaran: 2014-01-01 00:00:00.000

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

Keluaran: 2013-12-31 00:00:00.000

(Diuji pada MS SQL Server 2005 dan 2008 R2)

EDIT: Menurut komentar Adam, ini tidak dapat terjadi jika Anda membaca nilai tanggal dari tabel, tetapi itu bisa terjadi jika Anda memberikan nilai tanggal Anda sebagai literal (contoh: sebagai parameter dari prosedur tersimpan yang dipanggil melalui ADO.NET).

broslav
sumber
1
.999 tidak dapat disimpan dalam SQL Server dalam DATETIMEkolom. Yang tertinggi tersedia .997 Dari: msdn.microsoft.com/en-us/library/ms187819.aspx Anda akan melihat bahwa nilai dibulatkan untuk memiliki tempat keseribu ke 0, 3, atau 7. OP tidak akan melihat nilai dari tes Anda di tabel mereka.
Adam Wenger
Anda benar. Saya tidak bermaksud memposting ini sebagai jawaban untuk pertanyaan OP, tetapi sebagai komentar untuk dilihat orang lain, tetapi saya hanya punya 11 poin reputasi dan 15 diperlukan untuk berkomentar.
broslav
Dalam cuplikan pertama Anda, konstanta string secara implisit dikonversi ke datetime, di yang kedua Anda tetap string (dan 113 hanya diabaikan).
Andriy M
2

Strip waktu pada sisipan / pembaruan di tempat pertama. Sedangkan untuk konversi on-the-fly, tidak ada yang dapat mengalahkan fungsi pemeliharaan yang ditentukan pengguna:

select date_only(dd)

Implementasi date_onlybisa apa saja yang Anda suka - sekarang sudah disarikan dan kode panggilan jauh lebih bersih.

Anton Gogolev
sumber
Saya pernah menemukan pemicu untuk menggosok kali dari kolom yang dipilih. Jika datanya tidak buruk, Anda tidak perlu membersihkannya.
Philip Kelley
2
Ada kelemahan pada pendekatan UDF, mereka tidak SARGable. Jika digunakan dalam klausa JOINs atau WHERE, pengoptimal tidak dapat menggunakan INDEKS untuk meningkatkan kinerja. Menggunakan pendekatan DATEADD / DATEIFF, bagaimanapun, adalah SARGable dan akan dapat memperoleh manfaat dari INDEKS. (Rupanya metode FLOAT juga SARGable)
MatBailie
1
@MatBailie saya mohon berbeda! UDF jelas bukan SARGable, tetapi Dateadd juga tidak Konversi ke float! WHERE DateAdd(DateDiff(Column)) = @DateValuetidak akan menggunakan indeks. Di sisi lain, WHERE Column >= dbo.UDF(@DateValue) AND Column < dbo.UDF(@DateValue + 1) adalah SARGable. Jadi berhati-hatilah bagaimana Anda mengatakannya.
ErikE
2

Lihat pertanyaan ini:
Bagaimana saya bisa memotong datetime di SQL Server?

Apa pun yang Anda lakukan, jangan gunakan metode string . Itu tentang cara terburuk Anda bisa melakukannya.

Joel Coehoorn
sumber
Terima kasih, saya pikir ini harus ditanyakan sebelumnya. Meskipun aneh bahwa percobaan saya menunjukkan bahwa metode float sebenarnya lebih lambat 3,5% pada SQL Server 2008 daripada metode dateadd (dd, 0, datediff (dd, 0, getDate ())). Saya menjalankan tes saya berkali-kali untuk setiap metode dan server database tidak digunakan untuk hal lain pada saat itu.
Stephen Perelson
Katakan saja saya skeptis terhadap tolok ukur yang dilakukan oleh siapa saja yang belum menunjukkan bahwa mereka melakukan tolok ukur secara teratur dan dengan cara yang sangat ilmiah sebagai bagian dari pekerjaan mereka. Bahkan tolok ukur Thomas dalam tautan oleh gbn memiliki beberapa masalah yang jelas ketika Anda melihatnya. Itu tidak membuatnya salah, hanya saja tidak definitif. Metode pemain / lantai / pemain adalah cara tercepat yang diterima untuk waktu yang sangat lama, dan saya menduga itu pernah benar benar Yang mengatakan, saya mulai mempertimbangkannya kembali; terutama untuk sql server 2008, di mana itu sama sekali tidak perlu.
Joel Coehoorn
1
Metode string sangat mudah digunakan, dibaca, dan diingat. Itu adalah faktor yang sangat penting yang saya pikir Anda meremehkan!
Ben
1
@ JoelCoehoorn, convert style 121 disebut "ODBC Canonical". Itu tidak berbeda dengan susunan atau lokal. Trik string juga mudah digeneralisasi ke tahun, tahun + bulan, hari, jam atau menit.
Ben
1
@Ben Trik string mengajarkan pengembang untuk menggunakan konversi string. Mereka bekerja , tetapi matematika tanggal jauh, jauh lebih unggul, karena banyak alasan, tidak sedikit yang cepat - tetapi bahkan lebih, untuk apa belajar untuk bekerja dengan tanggal-sebagai-angka yang diberikan pada pengembang dan kemampuan mentalnya untuk menjadi cair dengan manipulasi angka dalam kode.
ErikE
2

Sudah dijawab tetapi tidak akan membuang ini di luar sana juga ... ini seharusnya juga membentuk sebelumnya dengan baik tetapi berfungsi dengan membuang desimal (yang menyimpan waktu) dari float dan mengembalikan hanya seluruh bagian (yang merupakan tanggal)

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

kedua kalinya saya menemukan solusi ini ... saya mengambil kode ini

Carter Cole
sumber
1
Konversi ke float tidak aman .
ErikE
2
CAST(round(cast(getdate()as real),0,1) AS datetime)

Metode ini tidak menggunakan fungsi string. Datepada dasarnya adalah tipe data nyata dengan digit sebelum desimal adalah pecahan sehari.

ini saya kira akan lebih cepat daripada banyak.

shantanu singh chauhan
sumber
1
Casting sebagai float tidak aman .
ErikE
2

Bagi saya kode di bawah ini selalu menjadi pemenang:

SELECT CONVERT(DATETIME, FLOOR(CONVERT(FLOAT,GETDATE())));
pengguna1920017
sumber
1
Pada dasarnya sama dengan saran @Gary McGill .
Andriy M
1
Casting sebagai float tidak aman .
ErikE
2

pilih CONVERT (char (10), GetDate (), 126)

Diego
sumber
Apa perbedaan utama saran Anda dari metode yang disebutkan dalam jawaban @ broslav atau dari metode yang ditentukan paling lambat di utas ini (tautan yang sama dengan jawaban yang diterima)?
Andriy M
1

Saya pikir maksud Anda cast(floor(cast(getdate()as float))as datetime)

real hanya 32-bit, dan bisa kehilangan beberapa informasi

Ini tercepat cast(cast(getdate()+x-0.5 as int)as datetime)

... meskipun hanya sekitar 10% lebih cepat(about 0.49 microseconds CPU vs. 0.58)

Ini direkomendasikan, dan membutuhkan waktu yang sama dalam pengujian saya sekarang: DATEADD(dd, DATEDIFF(dd, 0, getdate()), 0)

Dalam SQL 2008, fungsi SQL CLR adalah sekitar 5 kali lebih cepat daripada menggunakan fungsi SQL, pada 1,35 mikrodetik versus 6,5 mikroskopi, menunjukkan biaya panggilan fungsi yang jauh lebih rendah untuk fungsi SQL CLR dibandingkan dengan UDF SQL sederhana.

Dalam SQL 2005, fungsi SQL CLR adalah 16 kali lebih cepat, per pengujian saya, dibandingkan dengan fungsi lambat ini:

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

Bagaimana dengan select cast(cast my_datetime_field as date) as datetime)? Ini menghasilkan tanggal yang sama, dengan waktu yang ditentukan untuk 00:00, tetapi menghindari konversi ke teks dan juga menghindari pembulatan numerik eksplisit.

Drew
sumber
Mereka tidak sama. Jawaban lain menyarankan casting ke tanggal tanpa komponen waktu dan biarkan seperti itu. Posting saya membuatnya menjadi datetime dengan waktu tengah malam. Ada perbedaan besar; coba ekspor ke MS Excel dan Anda akan melihatnya menangani datetime jauh lebih baik daripada tanggal.
Dr. Drew
Yang pertama persis sama.
Mikael Eriksson
Ok, ya, saya melihat itu sekarang. Saya akan dengan senang hati menghapus jawaban saya sebagai duplikat, jika perlu.
Dr. Drew
1

Saya pikir jika Anda berpegang teguh pada TSQLhal ini, ini adalah cara tercepat untuk memotong waktu:

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

Saya menemukan metode pemotongan ini sekitar 5% lebih cepat daripada DateAddmetode ini. Dan ini dapat dengan mudah dimodifikasi untuk dibulatkan ke hari terdekat seperti ini:

select convert(datetime,ROUND(convert(float,[Modified]),0))
Jamie G
sumber
Konversi ke float tidak aman .
ErikE
1

Di sini saya membuat fungsi untuk menghapus beberapa bagian datetime untuk SQL Server. Pemakaian:

  • Param pertama adalah datetime untuk dilepas.
  • Param kedua adalah char:
    • s: putaran ke detik; menghapus milidetik
    • m: putaran ke menit; menghapus detik dan milidetik
    • h: putaran ke jam; menghapus menit, detik, dan milidetik.
    • d: putaran ke hari; menghapus jam, menit, detik, dan milidetik.
  • Mengembalikan datetime baru

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

Max Vargas
sumber
Terima kasih andriy! Saya tidak tahu rekomendasi saya tidak seefisien itu. Setidaknya itu berhasil, tetapi Anda benar.
Max Vargas
1

Kalau-kalau ada orang mencari versi Sybase di sini karena beberapa versi di atas tidak berfungsi

CAST(CONVERT(DATE,GETDATE(),103) AS DATETIME)
  • Diuji dalam I SQL v11 yang berjalan pada Adaptive Server 15.7
Alan
sumber
Ini lebih sesuai sebagai hasil edit pada jawaban yang diterima. Dengan 20 jawaban lain, ini akan dikubur dan hampir tidak dapat dihindarkan. Juga jawaban yang diterima menyebutkan penggunaan cast: Untuk SQL Server 2008+, Anda dapat melakukan CAST hingga saat ini. Atau gunakan saja tanggal sehingga tidak ada waktu untuk menghapus.
EWit
Akan lebih baik memposting ini sebagai jawaban untuk pertanyaan Sybase yang setara. Jika tidak ada pertanyaan seperti itu, Anda bebas untuk membuatnya (dan menjawabnya sendiri).
Andriy M
Selain itu, tidak ada gunanya menentukan parameter ketiga untuk CONVERT ketika Anda mengonversi a datetimeke date: tak satu pun dari mereka memiliki format yang melekat.
Andriy M
0

Jika memungkinkan, untuk hal-hal khusus seperti ini, saya suka menggunakan fungsi CLR.

Pada kasus ini:

[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;
    }
tjeuten
sumber
0

Saya, secara pribadi, hampir selalu menggunakan fungsi yang Ditentukan Pengguna untuk ini jika berurusan dengan SQL Server 2005 (atau versi yang lebih rendah), namun, perlu dicatat bahwa ada kelemahan spesifik untuk menggunakan UDF, terutama jika menerapkannya pada klausa WHERE (lihat di bawah dan komentar pada jawaban ini untuk perincian lebih lanjut). Jika menggunakan SQL Server 2008 (atau lebih tinggi) - lihat di bawah.

Bahkan, untuk sebagian besar database yang saya buat, saya menambahkan UDF ini tepat di dekat awal karena saya tahu ada 99% peluang saya akan membutuhkannya cepat atau lambat.

Saya membuat satu untuk "date only" & "time only" (walaupun "date only" satu adalah yang paling banyak digunakan dari keduanya).

Berikut ini beberapa tautan ke berbagai UDF terkait tanggal:

Essential SQL Server Tanggal, Waktu dan Fungsi DateTime
Dapatkan Fungsi Hanya Tanggal

Tautan terakhir itu menunjukkan tidak kurang dari 3 cara berbeda untuk mendapatkan tanggal hanya bagian dari bidang waktu dan menyebutkan beberapa pro dan kontra dari setiap pendekatan.

Jika menggunakan UDF, harus dicatat bahwa Anda harus mencoba menghindari menggunakan UDF sebagai bagian dari klausa WHERE dalam kueri karena ini akan sangat menghambat kinerja kueri. Alasan utama untuk ini adalah bahwa menggunakan UDF dalam klausa WHERE menjadikan klausa sebagai non-sargable , yang berarti bahwa SQL Server tidak lagi dapat menggunakan indeks dengan klausa itu untuk meningkatkan kecepatan eksekusi permintaan. Dengan merujuk pada penggunaan UDF saya sendiri, saya akan sering menggunakan kolom tanggal "mentah" dalam klausa WHERE, tetapi menerapkan UDF ke kolom SELECT. Dengan cara ini, UDF hanya diterapkan pada set-hasil yang difilter dan tidak setiap baris tabel sebagai bagian dari filter.

Tentu saja, pendekatan terbaik mutlak untuk ini adalah dengan menggunakan SQL Server 2008 (atau lebih tinggi) dan memisahkan tanggal dan waktu Anda , karena mesin basis data SQL Server kemudian secara asli menyediakan komponen tanggal dan waktu, dan secara efisien dapat meminta ini secara mandiri tanpa perlu UDF atau mekanisme lain untuk mengekstrak bagian tanggal atau waktu dari tipe datetime komposit.

CraigTP
sumber
Menggunakan UDF bisa bagus dalam beberapa situasi (seperti saat menggosok parameter). Tetapi dalam kebanyakan situasi itu adalah solusi yang mengerikan - menjalankan UDF sekali untuk setiap baris adalah cara untuk hanya membunuh kinerja permintaan, tanpa perlu!
ErikE
@ErikE - Saya tidak setuju, Erik, UDF adalah pembunuh kinerja yang mengapa saya mengatakan itu, jika Anda dapat menggunakan SQL Server 2008 atau lebih tinggi dan menggunakan datatype bawaan yang melakukan ini untuk Anda, itu akan menjadi solusi terbaik (baik dalam hal mencapai apa yang diperlukan dan dalam hal kinerja). Jika Anda terjebak dengan versi SQL Server yang lebih lama yang tidak mendukung ini, Anda akan memberikan sesuatu untuk mencapai persyaratan Anda.
CraigTP
Benar. Alangkah baiknya jika mesin database memberi kami sesuatu yang SARGable, tetapi lebih mudah untuk diungkapkan. Sementara itu, jika Anda sedang mencari nilai yang setiap saat selama sepanjang hari, ini masih merupakan solusi terbaik (untuk setidaknya versi SQL): WHERE DateColumn >= {TimeTruncatingExpression}(@DateValue) AND DateColumn < {TimeTruncatingExpression}(@DateValue + 1). Saya merasa harus mengatakan sesuatu karena Anda mengatakan "Saya hampir selalu menggunakan UDFs" tidak menjelaskan kekurangannya, atau cara membuat kueri hanya-tanggal SARGable.
ErikE
@ErikE - Jangan khawatir, Erik. Ketika saya telah menggunakan UDF, saya telah bekerja dengan set data kecil di mana kinerja bukan yang terpenting, atau lebih mungkin saya telah memfilter kueri terhadap bidang tanggal "mentah" (untuk memastikan sargabilitas) tetapi memilih kolom dengan UDF diterapkan. Karena ini biasanya set data kecil yang pernah difilter, menjalankan UDF di atas sejumlah kecil catatan ini bukanlah kinerja yang hebat. Yang mengatakan, Anda menaikkan poin yang sangat bagus dan saya telah memperbarui jawaban saya untuk mencerminkan hal ini.
CraigTP
-4

Saya akan menggunakan:

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

Dengan demikian secara efektif membuat bidang baru dari bidang tanggal yang sudah Anda miliki.

Jabu
sumber
2
Kenapa kamu ingin melakukan itu? Apakah Anda berpikir bahwa mengekstraksi bit dari suatu datetimenilai, mengubahnya menjadi string, menggabungkannya menjadi satu dan akhirnya mengonversi hasilnya kembali menjadi datetimelebih baik daripada misalnya melakukan perhitungan langsung pada yang asli datetime( metode DATEADD/ DATEDIFF)?
Andriy M
Juga, apa itu MMdan DD? Tidak ada fungsi seperti itu di SQL Server.
Andriy M