วิธีรวมวันที่และเวลาเข้ากับ datetime2 ใน SQL Server


48

รับส่วนประกอบดังนี้

DECLARE @D DATE = '2013-10-13'
DECLARE @T TIME(7) = '23:59:59.9999999'

วิธีที่ดีที่สุดในการรวมพวกเขาเพื่อสร้างDATETIME2(7)ผลลัพธ์ที่มีค่า'2013-10-13 23:59:59.9999999'คืออะไร?

บางสิ่งที่ไม่ทำงานแสดงอยู่ด้านล่าง


SELECT @D + @T 

วันที่ตัวดำเนินการชนิดข้อมูลไม่ถูกต้องสำหรับตัวดำเนินการเพิ่ม


SELECT CAST(@D AS DATETIME2(7)) + @T 

ตัวถูกดำเนินการชนิดข้อมูล datetime2 ไม่ถูกต้องสำหรับตัวดำเนินการเพิ่ม


SELECT DATEADD(NANOSECOND,DATEDIFF(NANOSECOND,CAST('00:00:00.0000000' AS TIME),@T),@D)

ฟังก์ชั่น Dateiff ส่งผลให้เกิดการล้น จำนวนของส่วนของวันที่ที่แยกอินสแตนซ์วันที่ / เวลาสองรายการมีขนาดใหญ่เกินไป ลองใช้ Dateiff ด้วยส่วนที่แม่นยำน้อยกว่า

* ล้นสามารถหลีกเลี่ยงได้ในฐานข้อมูล SQL Azure และ SQL Server 2016 DATEDIFF_BIGโดยใช้


SELECT CAST(@D AS DATETIME) + @T 

วันที่และเวลาของชนิดข้อมูลไม่เข้ากันในตัวดำเนินการเพิ่ม


SELECT CAST(@D AS DATETIME) + CAST(@T AS DATETIME)

ส่งคืนผลลัพธ์ แต่สูญเสียความแม่นยำ 2013-10-13 23:59:59.997

คำตอบ:


49

ดูเหมือนว่าจะทำงานและรักษาความแม่นยำไว้เช่นกัน:

SELECT DATEADD(day, DATEDIFF(day,'19000101',@D), CAST(@T AS DATETIME2(7)))

CASTการDATETIME2(7)แปลงTIME(7)ค่า ( @T) เพื่อDATETIME2ที่ส่วนวันที่'1900-01-01'ซึ่งเป็นค่าเริ่มต้นของวันที่และเวลาประเภท (ดูdatetime2และแสดงความคิดเห็น*ในCASTและCONVERTหน้า MSDN.)

* ... เมื่อข้อมูลตัวละครที่แสดงเฉพาะวันที่หรือเวลาเท่านั้นที่ถูกส่งไปยังประเภทข้อมูล datetime หรือ smalldatetime องค์ประกอบเวลาที่ไม่ระบุจะถูกตั้งค่าเป็น 00: 00: 00.000 และองค์ประกอบวันที่ไม่ได้ระบุถูกตั้งค่าเป็น 1900-01- 01 .

DATEADD()และDATEDIFF()ดูแลการทำงานของส่วนที่เหลือคือการเพิ่มความแตกต่างในวันที่ระหว่าง1900-01-01และDATEค่า ( @D)

ทดสอบที่: SQL-Fiddle


ตามที่สังเกตโดย@Quandaryนิพจน์ด้านบนจะถูกพิจารณาว่าเป็น SQL Server หากเราต้องการนิพจน์ที่กำหนดขึ้นพูดเพราะมันจะใช้สำหรับPERSISTEDคอลัมน์'19000101'**จำเป็นต้องถูกแทนที่ด้วย0หรือCONVERT(DATE, '19000101', 112):

CREATE TABLE date_time
( d DATE NOT NULL,
  t TIME(7) NOT NULL,
  dt AS DATEADD(day, 
                DATEDIFF(day, CONVERT(DATE, '19000101', 112), d), 
                CAST(t AS DATETIME2(7))
               ) PERSISTED
) ;

**: DATEDIFF(day, '19000101', d)ไม่ได้กำหนดไว้แล้วเนื่องจากเป็นการแปลงโดยอ้อมของสตริงเป็นDATETIMEและการแปลงจากสตริงเป็นวันที่และเวลาจะถูกกำหนดเฉพาะเมื่อมีการใช้สไตล์เฉพาะ


8

ฉันไปงานปาร์ตี้ช้า แต่วิธีนี้คล้ายกับคำตอบของ @ ypercubeหลีกเลี่ยงความต้องการใช้การแปลงสตริงใด ๆ (ซึ่งอาจมีราคาแพงกว่าการแปลงวันที่) เป็นสิ่งที่กำหนดและควรทำงานต่อไปถ้า MS เปลี่ยน ค่าวันที่เริ่มต้นจาก 1900-01-01 (แม้ว่าพวกเขาอาจจะไม่เปลี่ยนแปลงสิ่งนี้):

DECLARE @D DATE = SYSUTCDATETIME()
, @T TIME = SYSUTCDATETIME();

SELECT DATEADD(DAY, DATEDIFF(DAY, @T, @D), CONVERT(DATETIME2, @T));

หลักการคือการแปลงค่าเวลาเป็น datetime2 และจากนั้นเป็นวันที่มันจะตัดการหมดเวลาและกำหนดวันที่เริ่มต้นจากนั้นคุณลงวันที่นี้ด้วยค่าวันที่ของคุณที่จะได้รับวันที่จะเพิ่ม วันใน


แทนที่จะเป็น "DATEDIFF (วันที่ @T, @D)" ควรเป็น "DATEDIFF (วันที่ 0, @D)" ผลลัพธ์เหมือนกัน แต่ช่วยหลีกเลี่ยงความสับสน DateDiff (วัน, ... ) ปลดล็อกอาร์กิวเมนต์เป็นจำนวน int ต่ำสุดของวันดังนั้น @T จะถูกแปลงเป็น 0 อย่างไรก็ตาม
Dennis Gorelik

5

สำหรับ SQL Server 2012 ขึ้นไปมีฟังก์ชั่นDATETIME2FROMPARTS มันมีแบบฟอร์มนี้:

DATETIME2FROMPARTS(year, month, day, hour, minute, seconds, fractions, precision)

สำหรับข้อมูลตัวอย่างที่กำหนดสิ่งนี้จะกลายเป็น

select Answer = DATETIME2FROMPARTS(2013, 10, 13, 23, 59, 59, 9999999, 7);

ซึ่งส่งผลให้

Answer
---------------------------
2013-10-13 23:59:59.9999999

ชิ้นส่วนสามารถรับได้โดยใช้DATEPART ()ถ้าเริ่มต้นจากประเภทข้อมูลชั่วคราวหรือจากข้อความที่ใช้ในการสร้างค่าตัวอย่างในคำถาม


0

มันค่อนข้างโง่ของ SQL Server ที่จะไม่ปล่อยให้ตัวอย่างแรกของคุณทำงานและสิ่งนี้จะดูเหมือนโง่จริง ๆ เช่นกัน แต่ ...

select convert(datetime2, convert(nvarchar(max), @d) + ' ' + convert(nvarchar(max), @t));

0
SELECT mydate=CAST(CAST(@D AS nvarchar(max)) + ' ' + 
                   CAST(@T AS nvarchar (max)) 
              AS DATETIME2);

5
คุณเคยทดสอบสิ่งนี้หรือไม่? ใช้งานได้หรือไม่ มันได้รับผลกระทบจากการตั้งค่าภาษาหรือไม่?
ypercubeᵀᴹ

0

ฉันกำลังมองหาอย่างอื่นเมื่อฉันลงจอดที่นี่ คำถามนี้ค่อนข้างเก่า แต่มีความเห็นและกิจกรรมล่าสุด คิดว่าฉันจะแบ่งปันวิธีการง่ายๆที่คล้ายกับคำตอบ @Atario ที่ให้ แต่สั้นกว่าเล็กน้อยและบางคนอาจอ่านง่ายขึ้น:

declare @d date = '2013-10-13'
declare @t time(7) = '23:59:59.9999999'

select cast(concat(@d, ' ', @t) as datetime2(7))

-3

คุณสามารถตัดทอนด้วยการส่งถึง DATE เพื่อตัดทอนแล้วกลับสู่ DATETIME เพื่อเพิ่ม TIME

select CAST( cast(getdate() as date) as DATETIME)  + CAST(getdate() as TIME)

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