วิธีที่ดีที่สุดในการลบส่วนเวลาของวันที่และเวลาใน SQL Server


514

วิธีใดให้ประสิทธิภาพที่ดีที่สุดเมื่อเอาส่วนเวลาออกจากเขตข้อมูลวันที่ใน SQL Server

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

หรือ

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

วิธีที่สองส่งไบต์เพิ่มอีกสองสามวิธี แต่อาจไม่สำคัญเท่ากับความเร็วของการแปลง

ทั้งสองดูเหมือนจะเร็วมาก แต่อาจมีความแตกต่างของความเร็วเมื่อจัดการกับแถวนับแสนหรือมากกว่านั้น

นอกจากนี้เป็นไปได้ไหมว่ามีวิธีที่ดีกว่าในการกำจัดส่วนเวลาของวันที่และเวลาใน SQL?


1
ฉันได้ลองสิ่งนี้กับหนึ่งล้านบันทึกในตารางการผลิตของฉันและฉันไม่สามารถอ่านการแสดงได้อย่างแม่นยำ ทั้งสองวิธีแสดงจำนวนข้อมูลเท่ากันทุกประการ
Stephen Perelson

9
ใน 18,000,000 แถวนี่คือสิ่งที่ฉันพบ (SQL Server 2008): เมธอด b ช้ากว่าเมธอด a ประมาณ 24% CAST (FLOOR (CAST (getdate () AS FLOAT)) AS DATETIME) ช้าลง 3.5% เมื่อเทียบกับวิธี a เมธอด a น่าจะเป็นผู้ชนะโดยพิจารณาจากประสิทธิภาพ ขอบคุณทุกคำตอบที่ยอดเยี่ยม
Stephen Perelson

46
ทำไม heck จึงไม่มี SQL ที่มีฟังก์ชั่นในตัวให้ทำเช่นนี้? !!
Gary McGill

10
ประเภทข้อมูล DATE ใหม่ของ SQL 2008 จะจัดการสิ่งนี้
Philip Kelley

คำตอบ:


558

อย่างเคร่งครัดวิธีการaเป็นทรัพยากรที่น้อยที่สุด:

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

พิสูจน์แล้วว่า CPU มีความเข้มข้นน้อยกว่าในช่วงเวลาเดียวกันทั้งหมดหนึ่งล้านแถวโดยบางอันมีเวลามากเกินไป: วิธีที่มีประสิทธิภาพมากที่สุดใน SQL Server เพื่อรับวันที่จากวันที่ + เวลา?

ฉันเห็นการทดสอบที่คล้ายกันที่อื่นด้วยผลลัพธ์ที่คล้ายกัน

ฉันชอบ DATEADD / DATEDIFF เพราะ:

แก้ไข, ตุลาคม 2011

สำหรับ SQL Server 2008+ คุณสามารถโยนไปคือdate CAST(getdate() AS date)หรือเพียงแค่ใช้dateประเภทข้อมูลจึงไม่มีเวลาที่จะลบ

แก้ไข ม.ค. 2555

ตัวอย่างการทำงานของความยืดหยุ่นในการทำงานนี้: จำเป็นต้องคำนวณโดยการปัดเศษตัวเลขเวลาหรือวันที่ในเซิร์ฟเวอร์ sql

แก้ไขพฤษภาคม 2012

อย่าใช้สิ่งนี้ในส่วนคำสั่ง WHERE และสิ่งที่คล้ายกันโดยไม่ต้องคิด: การเพิ่มฟังก์ชั่นหรือ CAST ในคอลัมน์ทำให้การใช้ดัชนีไม่ถูกต้อง ดูหมายเลข 2 ได้ที่นี่: http://www.simple-talk.com/sql/t-sql-programming/ten-common-sql-programming-mistakes/

ตอนนี้มีตัวอย่างของเวอร์ชันที่ใหม่กว่าของ SQL Server optimiser ที่จัดการ CAST ให้ถูกต้อง แต่โดยทั่วไปจะเป็นความคิดที่ไม่ดี ...

แก้ไข ก.ย. 2018 สำหรับ 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 สำหรับการแก้ไขเดือนตุลาคม 2011 รหัสจะเป็นดังนี้: เลือกนักแสดง (GETDATE () ตามวันที่)
Choco Smith

1
สำหรับ SQL เวอร์ชันที่ใหม่กว่าการใช้วันที่แทนวันที่และเวลาจะหลีกเลี่ยงความจำเป็นในการจัดการกับชั่วโมง ใช้ตัวอย่างต่อไปนี้: ประกาศ noTime date = getdate (), withTime datetime = getdate () เลือก @ noTime, @ withTime
ozkary

1
การโยนตามวันที่ดีมากถ้าคุณแค่ต้องการวันที่ อย่างไรก็ตามบ่อยครั้งที่คุณต้องการวันที่ปัจจุบันตอนเที่ยงคืนเพื่อให้คุณสามารถจัดการวันที่เพิ่มเติมได้ DATEเวลาข้อมูลที่น่าสะพรึงกลัวที่เข้มงวดในสิ่งที่มันจะช่วยให้คุณทำในเรื่องเกี่ยวกับสิ่งที่ต้องการ DateAdd, DateDiff และมีปฏิสัมพันธ์กับวันที่ / เวลาชนิดข้อมูลอื่น ๆ สำหรับกรณีเหล่านั้นDATEADD()วิธีการที่ครองราชย์เป็นกษัตริย์
Xedni

สิ่งนี้ไม่สามารถใช้ได้กับทุกวัน ฉันป้อนผิดพลาด0218แทนที่จะ2018เป็นปีและDATEDIFFส่วนหนึ่งของคำสั่งของคุณมีข้อยกเว้นThe conversion of a datetime2 data type to a datetime data type resulted in an out-of-range datetime valueลอง:select DATEDIFF(dd, 0, convert(datetime2(0), '0218-09-12', 120))
Bernhard Döbler

1
@ BernhardDöblerในเดือนกรกฎาคม 2552 เมื่อฉันตอบว่า "0218" จะเป็นวันที่ที่ถูกต้องดังนั้นคุณจะไม่ได้มาไกลขนาดนี้ ด้วย "0" จะไม่แปลงเป็น 19000101 สำหรับ datetime2 ลองเลือกSELECT DATEDIFF(dd, '19000101', convert(datetime2(0), '0218-09-12', 120))
GBN

69

ใน SQL Server 2008 คุณสามารถใช้:

CONVERT(DATE, getdate(), 101)

13
อาร์กิวเมนต์ที่สามไม่ได้มีผลต่อการแปลงจาก a datetimeไปเป็น a dateดังนั้นโซลูชันของคุณจึงลดลงเหลือเพียงอย่างเดียวCONVERT(DATE,getdate())ซึ่งได้รับการแนะนำมากกว่าหนึ่งครั้ง
Andriy M

เพียงแค่ใช้CAST(GETDATE() AS DATE)หรือ ANSI อย่างเข้มงวดCAST(CURRENT_TIMESTAMP AS DATE)ซึ่งฉันคิดว่าไม่มีค่า อยู่กับคนแรก
Ivanzinho

52

แน่นอนว่านี่เป็นเธรดเก่า แต่ต้องทำให้เสร็จสมบูรณ์

จาก SQL 2008 คุณสามารถใช้ประเภทข้อมูล DATE เพื่อให้คุณสามารถทำได้:

SELECT CONVERT(DATE,GETDATE())

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

... ไม่ใช่ทางออกที่ดีตามความคิดเห็นด้านล่าง

ฉันจะลบคำตอบนี้ แต่ฉันจะทิ้งไว้ที่นี่เป็นตัวอย่างเคาน์เตอร์เพราะฉันคิดว่าคำอธิบายของผู้แสดงความคิดเห็นว่าทำไมความคิดที่ไม่ดียังคงมีประโยชน์


ดูคำตอบของ GBN หลายคนได้ตรวจสอบเรื่องนี้ DATETIMEs ไม่ถูกจัดเก็บเป็นแบบลอยตัวดังนั้นการใช้ DATEADD / DATEDIFF เพื่อหลีกเลี่ยงการบิดเบือนทางคณิตศาสตร์ที่ต้องใช้นักแสดงระหว่างประเภท
MatBailie

ฉันยอมรับได้ว่าคุณอาจต้องการหลีกเลี่ยงการแคสต์จาก DATETIME เป็น FLOAT ด้วยเหตุผลที่คุณอธิบาย แต่ในกรณีนั้นการแปลงโดยนัยจากศูนย์ในตัวเลือก OPs (a) เป็นปัญหาด้วยหรือไม่ อืม ... ฉันคิดว่าในกรณีนี้มันไม่ใช่ FLOAT และเซิร์ฟเวอร์น่าจะฉลาดพอที่จะทิ้งข้อมูลเวลา ตกลงฉันยอมรับ :-)
Gary McGill

0 คือการแปลงโดยนัยจากประเภทตัวเลข (INT ฉันเดา) เป็น DATETIME เนื่องจากเป็นนิพจน์ที่คงที่ แต่เครื่องมือเพิ่มประสิทธิภาพสามารถทำได้ในเวลาคอมไพล์สำหรับ Stored Procedure และต้องทำเพียงครั้งเดียวเพื่อเรียกใช้ SQL แบบไดนามิก ในระยะสั้นมีค่าใช้จ่ายเพียงครั้งเดียวสำหรับแบบสอบถาม FLOAT ตามที่มีค่าใช้จ่ายเท่าเทียมกันสำหรับทุกแถว
MatBailie

การร่ายเพื่อลอยนั้นไม่แน่นอนอย่างมาก คำตอบนี้ควรถูกลบ ไม่มีใครควรใช้รหัสนี้
usr

3
ไม่ต้องพูดถึงว่ามันไม่ปลอดภัยที่จะร่ายเพื่อลอยและกลับสู่ datetime - การลอยไม่มีความแม่นยำเพียงพอ ดังนั้นฉันคิดว่ามันไม่สามารถแนะนำได้เลย ดูโพสต์นี้สำหรับรายละเอียดเพิ่มเติม
ErikE

17

ใน SQL Server 2008 จะมีประเภทข้อมูล DATE (เช่นชนิดเวลา TIME)

CAST(GetDate() as DATE)

หรือ

declare @Dt as DATE = GetDate()

นี่คือสิ่งที่ฉันใช้และทำงานได้ดี ดูเหมือนว่าคำตอบที่ง่ายที่สุด มีข้อเสียมากกว่าการใช้งานร่วมกับแปลง /?
joelmdev

1
CAST และ CONVERT เทียบเท่าในฟังก์ชั่น ความแตกต่างคือ CAST เป็นส่วนหนึ่งของมาตรฐาน ANSI ในขณะที่ CONVERT นั้นเฉพาะกับ T-SQL ดังนั้นใช้ CAST เมื่อเป็นไปได้
ทรอย

@troy ฉันใช้ CAST เพราะฉันสามารถบันทึกตัวอักษรการพิมพ์ 3 ตัวและไวยากรณ์ได้ชัดเจนกว่า CONVERT ส่วนมาตรฐาน ANSI นั้นไม่มีค่า
Ivanzinho

8

ต่อไปนี้เป็นคำตอบอื่นจากคำถามซ้ำอีกข้อ:

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

วิธีหมายเลขมายากลนี้ทำงานได้เร็วกว่าวิธี DATEADD เล็กน้อย (ดูเหมือน ~ 10%)

เวลา CPU ในรอบหลายล้านระเบียน:

DATEADD   MAGIC FLOAT
500       453
453       360
375       375
406       360

แต่โปรดทราบว่าตัวเลขเหล่านี้อาจไม่เกี่ยวข้องเนื่องจากมีความเร็วสูงอยู่แล้ว ถ้าฉันไม่มีชุดบันทึกตั้งแต่ 100,000 ชุดขึ้นไปฉันจะไม่ได้รับเวลา CPU ในการอ่านสูงกว่าศูนย์

เมื่อพิจารณาถึงความจริงที่ว่า DateAdd นั้นมีความหมายสำหรับวัตถุประสงค์นี้และมีความแข็งแกร่งมากขึ้นฉันจะใช้ DateAdd


1
มันช่างน่ากลัว ฉันไม่เคยทำให้ข้อมูลของฉันตกอยู่ในความเสี่ยงเช่นนี้ ใครจะรู้ว่าสิ่งนี้ถูกต้องสำหรับชุดข้อมูลทั้งหมดไม่ใช่เฉพาะชุดทดสอบที่คุณทดสอบ
usr

@usr โอ้ถูกต้องมันเป็นเพียงหมายเลขเวทย์มนตร์และไม่ควรใช้ด้วยเหตุผลนั้น หากคุณต้องการตรวจสอบความถูกต้องเพียงแค่ระบุวันที่ที่เป็นไปได้ทั้งหมดสำหรับหนึ่งวันในตารางและตรวจสอบผลลัพธ์! นอกจากนี้ยังเห็นโพสต์นี้สำหรับข้อมูลเพิ่มเติม
ErikE

@ErikE เป็นจุดที่ดี คำตอบของคุณให้โอกาสในการใช้'12:00:00.003'ซึ่งฉันคิดว่าดีกว่ามาก
usr

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

4
ตัวเลือกที่ถูกต้องใช่ แนะนำให้มากกว่าหนึ่งครั้งในหัวข้อนี้
Andriy M

จริงๆแล้ววิธีแก้ปัญหานี้ง่ายที่สุดในการอ่าน goto ของฉัน
BelgoCanadian

5

ฉันชอบจริงๆ:

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

120โค้ดรูปแบบจะบีบบังคับวันที่เข้าสู่มาตรฐาน ISO 8601 นี้:

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

ใช้งานง่ายสุด ๆ ใน dplyr ( R) และ pandas ( Python)!


3

ระวัง!

วิธี a) และ b) ไม่เคยมีผลลัพธ์เดียวกันเสมอไป!

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

เอาท์พุท: 2014-01-01 00:00:00.000

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

เอาท์พุท: 2013-12-31 00:00:00.000

(ทดสอบบน MS SQL Server 2005 และ 2008 R2)

แก้ไข: ตามความเห็นของอดัมสิ่งนี้ไม่สามารถเกิดขึ้นได้หากคุณอ่านค่าวันที่จากตาราง แต่อาจเกิดขึ้นได้หากคุณให้ค่าวันที่ของคุณเป็นตัวอักษร (ตัวอย่าง: เป็นพารามิเตอร์ของกระบวนงานที่เก็บไว้ที่เรียกผ่าน ADO.NET)


1
.999 ไม่สามารถเก็บไว้ใน SQL Server ในDATETIMEคอลัมน์ ค่าสูงสุดที่มีอยู่คือ. 997 จาก: msdn.microsoft.com/en-us/library/ms187819.aspxคุณจะเห็นว่าค่าถูกปัดเศษให้มีตำแหน่งที่พันเป็น 0, 3 หรือ 7 OP จะไม่เห็น ค่าจากการทดสอบของคุณในตารางของพวกเขา
Adam Wenger

คุณถูก. ฉันไม่ได้ตั้งใจโพสต์สิ่งนี้เป็นคำตอบสำหรับคำถาม OP แต่เป็นความคิดเห็นที่คนอื่นเห็น แต่ฉันมีเพียง 11 คะแนนชื่อเสียงและ 15 จำเป็นสำหรับการแสดงความคิดเห็น
broslav

ในข้อมูลโค้ดแรกของคุณค่าคงที่สตริงจะถูกแปลงเป็น datetime โดยปริยายในครั้งที่สองของคุณจะยังคงเป็นสตริง (และ 113 จะถูกละเว้น)
Andriy M

2

สตริเวลาในการแทรก / ปรับปรุงในสถานที่แรก สำหรับการแปลงแบบทันทีนั้นไม่มีสิ่งใดสามารถเอาชนะความสามารถในการบำรุงรักษาที่ผู้ใช้กำหนดเองได้:

select date_only(dd)

การใช้งานdate_onlyสามารถเป็นอะไรก็ได้ที่คุณต้องการ - ตอนนี้มันถูกทำให้เป็นนามธรรมและรหัสการโทรนั้นสะอาดกว่ามาก


ฉันเคยคิดค้นทริกเกอร์เพื่อขัดเวลาจากคอลัมน์ที่เลือก หากข้อมูลไม่เลวคุณไม่จำเป็นต้องทำความสะอาด
Philip Kelley

2
มีข้อเสียของวิธีการ UDF พวกเขาไม่ใช่ SARGable หากใช้ในข้อ JOIN หรือ WHERE ตัวเพิ่มประสิทธิภาพจะไม่สามารถใช้ INDEX เพื่อปรับปรุงประสิทธิภาพได้ อย่างไรก็ตามการใช้วิธี DATEADD / DATEDIFF นั้นเป็น SARGable และจะได้รับประโยชน์จาก INDEX (เห็นได้ชัดว่าวิธีการ FLOAT เป็น SARGable เกินไป)
MatBailie

1
@MatBailie ฉันขอแตกต่างกัน! UDF ไม่ใช่ SARGable แน่นอน แต่ไม่มี Dateadd หรือ Convert to float! WHERE DateAdd(DateDiff(Column)) = @DateValueจะไม่ใช้ดัชนี ในอีกทางหนึ่งWHERE Column >= dbo.UDF(@DateValue) AND Column < dbo.UDF(@DateValue + 1) คือ SARGable ดังนั้นควรระวังให้ดี
ErikE

2

ดูคำถามนี้:
ฉันจะตัดทอนข้อมูลเวลาใน SQL Server ได้อย่างไร

สิ่งที่คุณทำไม่ได้ใช้วิธีการสตริง นั่นเป็นวิธีที่แย่ที่สุดที่คุณสามารถทำได้


ขอบคุณฉันคิดว่าสิ่งนี้ต้องถูกถามมาก่อน แปลกที่การทดลองของฉันชี้ให้เห็นว่าวิธีการลอยนั้นจริง ๆ แล้วช้าลง 3.5% ใน SQL Server 2008 กว่าวิธีการ dateadd (dd, 0, dateiff (dd, 0, getDate ())) ฉันรันการทดสอบหลายครั้งสำหรับแต่ละวิธีและเซิร์ฟเวอร์ฐานข้อมูลไม่ได้ใช้งานอย่างอื่นในเวลานั้น
Stephen Perelson

สมมติว่าฉันสงสัยในการวัดประสิทธิภาพของใครก็ตามที่ไม่ได้แสดงให้เห็นว่าพวกเขาทำการวัดประสิทธิภาพเป็นประจำและด้วยวิธีการทางวิทยาศาสตร์ที่เป็นส่วนหนึ่งของงานของพวกเขา แม้แต่มาตรฐานของโทมัสในลิงค์โดย gbn ก็มีปัญหาที่เห็นได้ชัดเมื่อคุณมองดู นั่นไม่ได้ทำให้มันผิดจำเป็นเสมอไป วิธีโยน / พื้น / นักแสดงเป็นวิธีที่เร็วที่สุดที่ยอมรับกันมานานมากและฉันก็สงสัยว่ามันเคยเป็นความจริง ที่กล่าวว่าฉันเริ่มที่จะพิจารณามัน โดยเฉพาะอย่างยิ่งสำหรับ sql server 2008 ซึ่งมันไม่จำเป็นเลย
Joel Coehoorn

1
เมธอดสตริงใช้งานง่ายมากอ่านและจดจำ นี่เป็นปัจจัยที่สำคัญมากซึ่งฉันคิดว่าคุณประเมินต่ำไป!
Ben

1
@JoelCoehoorn รูปแบบการแปลง 121 เรียกว่า "ODBC Canonical" มันไม่ได้แตกต่างกันกับการเปรียบเทียบหรือสถานที่ เคล็ดลับสตริงยังเป็นเรื่องง่ายที่จะพูดคุยกับปี, ปี + เดือน, วัน, ชั่วโมงหรือนาที
Ben

1
@Ben เคล็ดลับสตริงสอนให้นักพัฒนาใช้การแปลงสตริง พวกเขาทำงานแต่คณิตศาสตร์วันที่ไกลเกินกว่าด้วยเหตุผลหลายประการไม่น้อยกว่านั้นคือความเร็ว - แต่ยิ่งไปกว่านั้นสำหรับสิ่งที่เรียนรู้ที่จะทำงานกับ date-as-numbers confers กับนักพัฒนาและความสามารถทางจิตใจของเขา มีความคล่องแคล่วในการจัดการตัวเลขในโค้ด
ErikE

2

ตอบแล้ว แต่ไม่ได้โยนออกไปที่นั่นด้วย ... เรื่องนี้ก็ยังดี preforms ดี แต่มันทำงานโดยการทิ้งทศนิยม (ซึ่งเก็บเวลา) จากการลอยและกลับมาเพียงส่วนหนึ่งทั้งหมด (ซึ่งเป็นวันที่)

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

ครั้งที่สองที่ฉันพบวิธีนี้ ... ฉันคว้ารหัสนี้ออก


1
แปลงไปลอยไม่ปลอดภัย
ErikE

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

วิธีนี้ไม่ได้ใช้ฟังก์ชั่นสตริง Dateเป็นประเภทข้อมูลจริงที่มีตัวเลขก่อนทศนิยมเป็นเศษส่วนของวัน

ฉันเดาว่าจะเร็วกว่าเยอะ


1
หล่อเป็นลอยไม่ปลอดภัย
ErikE


2

เลือก CONVERT (อักขระ (10), GetDate (), 126)


อะไรคือข้อแตกต่างที่สำคัญของข้อเสนอแนะของคุณจากวิธีการที่กล่าวถึงในคำตอบของ @ broslav หรือจากวิธีการที่พิจารณาว่าช้าที่สุดในเธรดนี้ (ลิงก์เดียวกันกับคำตอบที่ยอมรับ)
Andriy M

1

ฉันคิดว่าคุณหมายถึง cast(floor(cast(getdate()as float))as datetime)

จริงเป็นเพียง 32 บิตและอาจสูญเสียข้อมูลบางอย่าง

นี่คือเร็วที่สุด cast(cast(getdate()+x-0.5 as int)as datetime)

... แม้ว่าจะเร็วกว่าประมาณ 10% เท่านั้น(about 0.49 microseconds CPU vs. 0.58)

สิ่งนี้แนะนำและใช้เวลาในการทดสอบของฉันตอนนี้: DATEADD(dd, DATEDIFF(dd, 0, getdate()), 0)

ใน SQL 2008 ฟังก์ชัน SQL CLR เร็วกว่าการใช้ฟังก์ชัน SQL ประมาณ 5 เท่าคือที่ 1.35 ไมโครวินาทีเทียบกับ 6.5 microsections แสดงค่าใช้จ่ายการเรียกฟังก์ชันที่ต่ำกว่ามากสำหรับฟังก์ชัน SQL CLR กับ SQL UDF แบบง่าย

ใน SQL 2005 ฟังก์ชัน SQL CLR นั้นเร็วกว่าการทดสอบของฉัน 16 เท่าเมื่อเทียบกับฟังก์ชันช้านี้:

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

1

แล้วไงselect cast(cast my_datetime_field as date) as datetime)ล่ะ นี่เป็นผลลัพธ์ในวันเดียวกันโดยมีการตั้งเวลาเป็น 00:00 แต่หลีกเลี่ยงการแปลงเป็นข้อความและหลีกเลี่ยงการปัดเศษตัวเลขที่ชัดเจน



พวกเขาไม่เหมือนกัน คำตอบอื่น ๆ แนะนำให้ส่งไปยังวันที่โดยไม่มีเวลาและปล่อยให้เป็นเช่นนั้น การโพสต์ของฉันตั้งค่าเป็นวันที่และเวลาเที่ยงคืน มีความแตกต่างใหญ่คือ; ลองส่งออกไปยัง MS Excel แล้วคุณจะเห็นว่าจัดการวันที่และเวลาได้ดีกว่าวันที่
ดร. Drew

อันแรกเหมือนกันหมด
Mikael Eriksson

ตกลงใช่ฉันเห็นตอนนี้แล้ว ฉันยินดีที่จะลบคำตอบของฉันซ้ำซ้อนหากจำเป็น
Dr. Drew

1

ฉันคิดว่าถ้าคุณยึดติดกับTSQLสิ่งนี้เป็นวิธีที่เร็วที่สุดในการตัดเวลา:

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

ฉันพบว่าวิธีการตัดนี้เร็วกว่าDateAddวิธีประมาณ 5% และนี่สามารถแก้ไขได้อย่างง่ายดายเพื่อปัดเศษเป็นวันที่ใกล้ที่สุดดังนี้:

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

แปลงไปลอยไม่ปลอดภัย
ErikE

1

ที่นี่ฉันทำฟังก์ชั่นเพื่อลบบางส่วนของวันที่และเวลาสำหรับ SQL Server การใช้งาน:

  • พารามิเตอร์แรกคือวันที่และเวลาที่จะถอด
  • พารามิเตอร์ที่สองคือตัวอักษร:
    • s: ปัดเศษเป็นวินาที ลบมิลลิวินาที
    • m: ปัดเศษเป็นนาที ลบวินาทีและมิลลิวินาที
    • h: ปัดเศษเป็นชั่วโมง; ลบนาทีวินาทีและมิลลิวินาที
    • d: ปัดเศษเป็นวัน ลบชั่วโมงนาทีวินาทีและมิลลิวินาที
  • ส่งคืน datetime ใหม่

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


ขอบคุณ Andriy! ฉันไม่ทราบว่าคำแนะนำของฉันไม่มีประสิทธิภาพ อย่างน้อยก็ใช้งานได้ แต่คุณพูดถูก
Max Vargas

1

ในกรณีที่มีใครบางคนกำลังมองหาเวอร์ชั่น Sybase ที่นี่เนื่องจากหลายเวอร์ชันด้านบนใช้งานไม่ได้

CAST(CONVERT(DATE,GETDATE(),103) AS DATETIME)
  • ทดสอบใน I SQL v11 ที่ทำงานบน Adaptive Server 15.7

นี่เป็นการดียิ่งกว่าเป็นการแก้ไขคำตอบที่ยอมรับ ด้วย 20 คำตอบอื่น ๆ นี้จะถูกฝังอยู่และไม่สามารถแยกได้ นอกจากนี้คำตอบที่ได้รับการยอมรับยังกล่าวถึงการใช้งานcast: สำหรับ SQL Server 2008+ คุณสามารถใช้ CAST จนถึงปัจจุบัน หรือเพียงแค่ใช้วันที่จึงไม่มีเวลาที่จะลบ
EWit

เป็นการดีที่สุดที่จะโพสต์สิ่งนี้เป็นคำตอบสำหรับคำถาม Sybase ที่เทียบเท่า หากไม่มีคำถามดังกล่าวคุณมีอิสระที่จะสร้าง (และตอบคำถามด้วยตนเอง)
Andriy M

นอกจากนี้ยังเป็นจุดหมายเพื่อระบุพารามิเตอร์ที่สามการแปลงเมื่อคุณกำลังแปลงdatetimeไปdate: ค่าของคนเหล่านั้นมีรูปแบบธรรมชาติ
Andriy M

0

ถ้าเป็นไปได้สำหรับสิ่งพิเศษเช่นนี้ฉันชอบใช้ฟังก์ชั่น CLR

ในกรณีนี้:

[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

โดยส่วนตัวแล้วฉันมักจะใช้ฟังก์ชั่นที่กำหนดโดยผู้ใช้สำหรับสิ่งนี้หากจัดการกับ SQL Server 2005 (หรือรุ่นที่ต่ำกว่า) อย่างไรก็ตามควรสังเกตว่ามีข้อเสียเปรียบเฉพาะสำหรับการใช้ UDF โดยเฉพาะอย่างยิ่งถ้าใช้กับคำสั่ง WHERE ความคิดเห็นเกี่ยวกับคำตอบนี้สำหรับรายละเอียดเพิ่มเติม) หากใช้ SQL Server 2008 (หรือสูงกว่า) - ดูด้านล่าง

ในความเป็นจริงสำหรับฐานข้อมูลส่วนใหญ่ที่ฉันสร้างฉันเพิ่ม UDF เหล่านี้ในช่วงเริ่มต้นเนื่องจากฉันรู้ว่ามีโอกาส 99% ที่ฉันจะต้องการพวกเขาไม่ช้าก็เร็ว

ฉันสร้างหนึ่งสำหรับ "วันที่เท่านั้น" & "เวลาเท่านั้น" (แม้ว่า "วันที่เท่านั้น" จะเป็นวันที่มีคนใช้มากที่สุดสองคน)

นี่คือลิงก์บางส่วนไปยัง UDF ที่เกี่ยวข้องกับวันที่:

ฟังก์ชัน SQL Server วันที่, เวลาและ DateTime ที่สำคัญรับฟังก์ชัน
วันที่เท่านั้น

ลิงค์สุดท้ายนั้นแสดงวิธีการรับวันที่ไม่น้อยกว่า 3 วิธีเพียงส่วนหนึ่งของเขตข้อมูลวันที่และกล่าวถึงข้อดีข้อเสียของแต่ละวิธี

หากใช้ UDF ควรสังเกตว่าคุณควรพยายามหลีกเลี่ยงการใช้ UDF เป็นส่วนหนึ่งของส่วนคำสั่ง WHERE ในแบบสอบถามเนื่องจากจะทำให้ประสิทธิภาพการทำงานของแบบสอบถามลดลงอย่างมาก เหตุผลหลักสำหรับการทำเช่นนี้คือการใช้ UDF ใน WHERE clause ทำให้ clause เป็นnon-sargableซึ่งหมายความว่า SQL Server ไม่สามารถใช้ดัชนีที่มี clause นั้นอีกต่อไปเพื่อปรับปรุงความเร็วในการประมวลผลแบบสอบถาม จากการอ้างอิงถึงการใช้งาน UDF ของตัวเองฉันมักจะใช้คอลัมน์วันที่ "ดิบ" ภายในส่วนคำสั่ง WHERE แต่ใช้ UDF กับคอลัมน์ที่เลือก ด้วยวิธีนี้ UDF จะใช้กับชุดผลลัพธ์ที่กรองเท่านั้นและไม่ใช่ทุกแถวของตารางเป็นส่วนหนึ่งของตัวกรอง

แน่นอนว่าวิธีที่ดีที่สุดสำหรับการใช้ SQL Server 2008 (หรือสูงกว่า) และแยกวันที่และเวลาของคุณออกเนื่องจากเครื่องมือฐานข้อมูลของ SQL Server นั้นให้ส่วนประกอบวันที่และเวลาแต่ละวันและสามารถค้นหาสิ่งเหล่านี้ได้อย่างอิสระ โดยไม่จำเป็นต้องมี UDF หรือกลไกอื่น ๆ เพื่อแยกส่วนวันที่หรือเวลาจากประเภทวันที่และเวลา


การใช้ UDF สามารถทำได้ดีในบางสถานการณ์ (เช่นเมื่อพารามิเตอร์การขัด) แต่ในสถานการณ์ส่วนใหญ่มันเป็นคำตอบที่น่ากลัว - การรัน UDF หนึ่งครั้งสำหรับแต่ละแถวเป็นวิธีที่จะฆ่าประสิทธิภาพของการสืบค้นโดยไม่จำเป็นต้องใช้มัน!
ErikE

@ErikE - ฉันไม่เห็นด้วย Erik, UDF เป็นนักฆ่าประสิทธิภาพซึ่งเป็นเหตุผลที่ฉันบอกว่าถ้าคุณสามารถใช้ SQL Server 2008 หรือสูงกว่าและใช้ประเภทข้อมูลในตัวที่เหมาะกับคุณนั่นจะเป็นทางออกที่ดีที่สุด (ทั้งในแง่ของการบรรลุสิ่งที่จำเป็นและในแง่ของประสิทธิภาพ) หากคุณติดอยู่กับ SQL Server รุ่นเก่าที่ไม่สนับสนุนสิ่งนี้คุณจะต้องยอมแพ้บางอย่างเพื่อให้บรรลุความต้องการของคุณ
CraigTP

จริง มันจะดีถ้าโปรแกรมฐานข้อมูลให้สิ่งที่เป็น SARGable แต่ง่ายต่อการแสดง ในขณะเดียวกันถ้าคุณกำลังมองหาค่าที่เวลาใด ๆ ในระหว่างทั้งวันนี้ยังคงเป็นทางออกที่ดีที่สุด (อย่างน้อยรุ่นเก่าของ WHERE DateColumn >= {TimeTruncatingExpression}(@DateValue) AND DateColumn < {TimeTruncatingExpression}(@DateValue + 1)SQL): ฉันรู้สึกเหมือนฉันต้องพูดอะไรบางอย่างตั้งแต่ที่คุณพูดว่า "ฉันมักจะใช้ UDF" ไม่ได้อธิบายถึงข้อเสียเปรียบใด ๆ และวิธีที่จะทำให้การสืบค้นเฉพาะวันที่ SARGable
ErikE

@ErikE - ไม่ต้องกังวลเอริค เมื่อฉันใช้ UDF ฉันได้ทำงานกับชุดข้อมูลขนาดเล็กซึ่งประสิทธิภาพไม่ได้เป็นที่น่าพอใจหรือมีแนวโน้มว่าฉันได้กรองการสืบค้นกับเขตข้อมูลวันที่ "ดิบ" (เพื่อให้แน่ใจว่าสามารถระบุได้) แต่เลือกคอลัมน์ เมื่อใช้ UDF แล้ว เนื่องจากเหล่านี้มักจะเป็นชุดข้อมูลขนาดเล็กเมื่อถูกกรองการเรียกใช้ UDF สำหรับบันทึกจำนวนน้อยนี้จึงไม่เป็นผลกระทบต่อประสิทธิภาพการทำงาน ที่กล่าวว่าคุณยกจุดดีมากและฉันได้ปรับปรุงคำตอบของฉันเพื่อสะท้อนนี้
CraigTP

-4

ฉันจะใช้:

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

ดังนั้นการสร้างเขตข้อมูลใหม่อย่างมีประสิทธิภาพจากเขตข้อมูลวันที่คุณมีอยู่แล้ว


2
ทำไมคุณจะทำเช่นนั้น? คุณคิดว่าการแตกบิตจากdatetimeค่าแปลงเป็นสตริงเชื่อมต่อกันและในที่สุดการแปลงผลลัพธ์กลับdatetimeเป็นดีกว่าเช่นทำการคำนวณโดยตรงกับต้นฉบับdatetime(the DATEADD/ DATEDIFFmethod) หรือไม่
Andriy M

นอกจากนี้อะไรMMและDD? ไม่มีฟังก์ชั่นดังกล่าวใน SQL Server
Andriy M
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.