Tạo một ngày từ ngày tháng và năm với T-SQL


265

Tôi đang cố gắng chuyển đổi một ngày với các phần riêng lẻ, chẳng hạn như 12, 1, 2007 thành một datetime trong SQL Server 2005. Tôi đã thử như sau:

CAST(DATEPART(year, DATE)+'-'+ DATEPART(month, DATE) +'-'+ DATEPART(day, DATE) AS DATETIME)

nhưng điều này dẫn đến sai ngày. Cách chính xác để biến ba giá trị ngày thành định dạng datetime thích hợp.


8
Vui lòng xem xét việc thay đổi câu trả lời được chấp nhận của bạn weblogs.sqlteam.com/jeffs/archive 2007/09/10 / Giả
Brian Webster

DATEFROMPARTS (năm, tháng, ngày)
Kate

Câu trả lời:


175

Giả sử y, m, dlà tất cả int, làm thế nào về:

CAST(CAST(y AS varchar) + '-' + CAST(m AS varchar) + '-' + CAST(d AS varchar) AS DATETIME)

Vui lòng xem câu trả lời khác của tôi cho SQL Server 2012 trở lên


Xấu nhất. Soạn tin tôi từ ngày 1 tháng 1 năm 0001
Oleg Dok

24
Oleg SQL Server DateTime không quay trở lại sau đó 1753-01-01 gì đó.
CodeMonkey

2
Câu trả lời này phụ thuộc vào cài đặt định dạng ngày, phụ thuộc vào cài đặt khu vực của máy chủ của bạn nếu bạn không chỉ định. Các yyyymmddđịnh dạng hoạt động bất kể những cài đặt. "Một chuỗi sáu hoặc tám chữ số luôn được hiểu là ymd ." docs.microsoft.com/en-us/sql/t-sql/data-types/NH Xem câu trả lời này: stackoverflow.com/a/46064419/2266979
Riley Major

339

Thử cái này:

Declare @DayOfMonth TinyInt Set @DayOfMonth = 13
Declare @Month TinyInt Set @Month = 6
Declare @Year Integer Set @Year = 2006
-- ------------------------------------
Select DateAdd(day, @DayOfMonth - 1, 
          DateAdd(month, @Month - 1, 
              DateAdd(Year, @Year-1900, 0)))

Nó cũng hoạt động, đã thêm lợi ích của việc không thực hiện bất kỳ chuyển đổi chuỗi nào, do đó, nó xử lý số học thuần túy (rất nhanh) và nó không phụ thuộc vào bất kỳ định dạng ngày nào. Điều này tận dụng thực tế là đại diện bên trong của SQL Server cho các giá trị thời gian và thời gian nhỏ là hai phần giá trị phần đầu tiên là số nguyên biểu thị số ngày kể từ ngày 1 tháng 1 năm 1900 và phần thứ hai là phần thập phân biểu thị phần phân số của một ngày (đối với thời gian) --- Vì vậy, giá trị số nguyên 0 (không ) luôn dịch trực tiếp vào nửa đêm ngày 1 tháng 1 năm 1900 ...

hoặc, nhờ đề xuất từ ​​@brinary,

Select DateAdd(yy, @Year-1900,  
       DateAdd(m,  @Month - 1, @DayOfMonth - 1)) 

Được chỉnh sửa vào tháng 10 năm 2014. Theo ghi nhận của @cade Roux, SQL 2012 hiện có chức năng tích hợp:
DATEFROMPARTS(year, month, day)
thực hiện điều tương tự.

Đã chỉnh sửa ngày 3 tháng 10 năm 2016, (Cảm ơn @bambams vì đã nhận thấy điều này và @brinary đã sửa nó), Giải pháp cuối cùng, được đề xuất bởi @brinary. dường như không hoạt động trong nhiều năm, trừ khi việc bổ sung được thực hiện trước

select dateadd(month, @Month - 1, 
     dateadd(year, @Year-1900, @DayOfMonth - 1)); 

36
@Brandon, bạn nên đánh dấu đây là câu trả lời này thay thế. Đó là cái tốt nhất. Làm điều đó như một dịch vụ cho các trình đọc StackOverflow khác.
Bill Paetzke

3
Hoạt động trong những năm nhuận: chọn dateadd (mm, (@ y-1900) * 12 + @m - 1,0) + (@ d-1)
ẩn

8
Kết quả trong một giá trị ngày giả nhưng hợp lệ khi được thông qua kết hợp các giá trị không hợp lệ @Year = 2001, ví dụ , @Month = 13@DayOfMonth = 32kết quả là 2002-02-01T00:00:00.000. Câu trả lời được chấp nhận (bởi Cade Roux) tạo ra một lỗi, hữu ích hơn.
onedaywhen

6
Bạn không phải bắt đầu bằng 0 và thêm ngày. Bạn có thể bắt đầu trực tiếp với @ DayOfMonth-1, sau đó thêm tháng và năm. Đó là một ngày ít DateAdd ()!
brianary

2
Đầu tôi vẫn quay cuồng - thực sự không có cách nào gọn gàng hơn để làm điều này? (Tôi được giao nhiệm vụ sửa một truy vấn trong SQL Server 2005)
Peter Perháč

241

SQL Server 2012 có chức năng DATEFROMPARTS mới tuyệt vời và được chờ đợi từ lâu (sẽ gây ra lỗi nếu ngày không hợp lệ - phản đối chính của tôi đối với giải pháp dựa trên DATEADD cho vấn đề này):

http://msdn.microsoft.com/en-us/l Library / hh213228.aspx

DATEFROMPARTS(ycolumn, mcolumn, dcolumn)

hoặc là

DATEFROMPARTS(@y, @m, @d)

11
Bên cạnh đó, đề cập đến câu hỏi ban đầu, nơi Datetime đối tượng được đề cập đến, đó cũng là một chức năng gọi là DATETIMEFROMPARTS: msdn.microsoft.com/pl-pl/library/hh213233%28v=sql.110%29.aspx
Maciej Jaśniaczyk

116

Hoặc chỉ sử dụng một hàm dữ liệu duy nhất:

DECLARE @day int, @month int, @year int
SELECT @day = 4, @month = 3, @year = 2011

SELECT dateadd(mm, (@year - 1900) * 12 + @month - 1 , @day - 1)

4
trả lời tốt nhất IMO. Có tất cả những lợi thế của câu trả lời của Charles, và ngắn hơn nhiều.
Michael

1
Đây là sạch nhất và đơn giản nhất. Và nó cũng không gây ra lỗi khi giá trị ngày nằm ngoài phạm vi. Altho tùy thuộc vào hoàn cảnh, một lỗi có thể được mong muốn, vì vậy chỉ cần lưu ý rằng khoảng im lặng này và các giá trị tháng nằm ngoài phạm vi dự kiến.
Shawn Kovac

17

Sql Server 2012 có chức năng sẽ tạo ngày dựa trên các phần ( DATEFROMPARTS ). Đối với phần còn lại của chúng tôi, đây là một hàm db tôi đã tạo sẽ xác định ngày từ các phần (cảm ơn @Charles) ...

IF EXISTS (SELECT * FROM dbo.sysobjects WHERE id = object_id(N'[dbo].[func_DateFromParts]'))
    DROP FUNCTION [dbo].[func_DateFromParts]
GO

CREATE FUNCTION [dbo].[func_DateFromParts]
(
    @Year INT,
    @Month INT,
    @DayOfMonth INT,
    @Hour INT = 0,  -- based on 24 hour clock (add 12 for PM :)
    @Min INT = 0,
    @Sec INT = 0
)
RETURNS DATETIME
AS
BEGIN

    RETURN DATEADD(second, @Sec, 
            DATEADD(minute, @Min, 
            DATEADD(hour, @Hour,
            DATEADD(day, @DayOfMonth - 1, 
            DATEADD(month, @Month - 1, 
            DATEADD(Year, @Year-1900, 0))))))

END

GO

Bạn có thể gọi nó như thế này ...

SELECT dbo.func_DateFromParts(2013, 10, 4, 15, 50, DEFAULT)

Trả về ...

2013-10-04 15:50:00.000

12

Hãy thử CHUYỂN ĐỔI thay vì CAST.

CONVERT cho phép tham số thứ ba cho biết định dạng ngày.

Danh sách các định dạng ở đây: http://msdn.microsoft.com/en-us/l Library / ms187928.aspx

Cập nhật sau khi câu trả lời khác đã được chọn là câu trả lời "đúng":

Tôi thực sự không hiểu tại sao câu trả lời được chọn rõ ràng phụ thuộc vào cài đặt NLS trên máy chủ của bạn mà không chỉ ra hạn chế này.


Đồng ý định dạng cần phải đủ điều kiện, ví dụ CONVERT (datetime2, CAST (@year AS varchar) + '.' + CAST (@month AS varchar) + '.' + CAST (@day AS varchar), 102)
Tony Wall

9

Bạn cũng có thể dùng

select DATEFROMPARTS(year, month, day) as ColDate, Col2, Col3 
From MyTable Where DATEFROMPARTS(year, month, day) Between @DateIni and @DateEnd

Hoạt động trong SQL kể từ ver.2012 và AzureQuery


6

An toàn hơn và gọn gàng hơn khi sử dụng điểm bắt đầu rõ ràng '19000101'

create function dbo.fnDateTime2FromParts(@Year int, @Month int, @Day int, @Hour int, @Minute int, @Second int, @Nanosecond int)
returns datetime2
as
begin
    -- Note! SQL Server 2012 includes datetime2fromparts() function
    declare @output datetime2 = '19000101'
    set @output = dateadd(year      , @Year - 1900  , @output)
    set @output = dateadd(month     , @Month - 1    , @output)
    set @output = dateadd(day       , @Day - 1      , @output)
    set @output = dateadd(hour      , @Hour         , @output)
    set @output = dateadd(minute    , @Minute       , @output)
    set @output = dateadd(second    , @Second       , @output)
    set @output = dateadd(ns        , @Nanosecond   , @output)
    return @output
end

Tại sao không sử dụng chỉ declare @output datetime2 = 0và thay vì @Year - 1900sử dụng @Year - DATEPART(year,0);? Điều này hoạt động mà không có bất kỳ phôi trong SQL Server 2008 và rõ ràng hơn nhiều.
tsionyx

Bởi vì điều đó sẽ không làm việc. Bạn không thể truyền 0 đến datetime2. Mã của bạn sẽ trả về "Kiểu toán tử clash: int không tương thích với datetime2"
Jack

4

Nếu bạn không muốn giữ các chuỗi bên ngoài nó, điều này cũng hoạt động (Đặt nó vào một hàm):

DECLARE @Day int, @Month int, @Year int
SELECT @Day = 1, @Month = 2, @Year = 2008

SELECT DateAdd(dd, @Day-1, DateAdd(mm, @Month -1, DateAdd(yy, @Year - 2000, '20000101')))

4

Tôi thêm giải pháp một dòng nếu bạn cần một datetime từ cả hai phần ngày và giờ :

select dateadd(month, (@Year -1900)*12 + @Month -1, @DayOfMonth -1) + dateadd(ss, @Hour*3600 + @Minute*60 + @Second, 0) + dateadd(ms, @Millisecond, 0)

3

Thử

CAST(STR(DATEPART(year, DATE))+'-'+ STR(DATEPART(month, DATE)) +'-'+ STR(DATEPART(day, DATE)) AS DATETIME)

2

Đối với các phiên bản SQL Server dưới 12, tôi có thể khuyên bạn nên sử dụng CASTkết hợp vớiSET DATEFORMAT

-- 26 February 2015
SET DATEFORMAT dmy
SELECT CAST('26-2-2015' AS DATE)

SET DATEFORMAT ymd
SELECT CAST('2015-2-26' AS DATE)

cách bạn tạo ra các chuỗi đó là tùy thuộc vào bạn


1

Hãy thử truy vấn này:

    SELECT SUBSTRING(CONVERT(VARCHAR,JOINGDATE,103),7,4)AS
    YEAR,SUBSTRING(CONVERT(VARCHAR,JOINGDATE,100),1,2)AS
MONTH,SUBSTRING(CONVERT(VARCHAR,JOINGDATE,100),4,3)AS DATE FROM EMPLOYEE1

Kết quả:

2014    Ja    1
2015    Ja    1
2014    Ja    1
2015    Ja    1
2012    Ja    1
2010    Ja    1
2015    Ja    1


0

Cá nhân tôi thích Chuỗi con hơn vì nó cung cấp các tùy chọn làm sạch và khả năng phân tách chuỗi khi cần. Giả định là dữ liệu có định dạng 'dd, mm, yyyy'.

--2012 and above
SELECT CONCAT (
        RIGHT(REPLACE(@date, ' ', ''), 4)
        ,'-'
        ,RIGHT(CONCAT('00',SUBSTRING(REPLACE(@date, ' ', ''), CHARINDEX(',', REPLACE(@date, ' ', '')) + 1, LEN(REPLACE(@date, ' ', '')) - CHARINDEX(',', REPLACE(@date, ' ', '')) - 5)),2)
        ,'-'
        ,RIGHT(CONCAT('00',SUBSTRING(REPLACE(@date, ' ', ''), 1, CHARINDEX(',', REPLACE(@date, ' ', '')) - 1)),2)
        )

--2008 and below
SELECT   RIGHT(REPLACE(@date, ' ', ''), 4)
        +'-'
        +RIGHT('00'+SUBSTRING(REPLACE(@date, ' ', ''), CHARINDEX(',', REPLACE(@date, ' ', '')) + 1, LEN(REPLACE(@date, ' ', '')) - CHARINDEX(',', REPLACE(@date, ' ', '')) - 5),2)
        +'-'
        +RIGHT('00'+SUBSTRING(REPLACE(@date, ' ', ''), 1, CHARINDEX(',', REPLACE(@date, ' ', '')) - 1),2)

Dưới đây là một minh chứng về cách nó có thể bị kiện nếu dữ liệu được lưu trữ trong một cột. Không cần phải nói, lý tưởng của nó là kiểm tra tập kết quả trước khi áp dụng cho cột

DECLARE @Table TABLE (ID INT IDENTITY(1000,1), DateString VARCHAR(50), DateColumn DATE)

INSERT INTO @Table
SELECT'12, 1, 2007',NULL
UNION
SELECT'15,3, 2007',NULL
UNION
SELECT'18, 11 , 2007',NULL
UNION
SELECT'22 , 11, 2007',NULL
UNION
SELECT'30, 12, 2007  ',NULL

UPDATE @Table
SET DateColumn = CONCAT (
        RIGHT(REPLACE(DateString, ' ', ''), 4)
        ,'-'
        ,RIGHT(CONCAT('00',SUBSTRING(REPLACE(DateString, ' ', ''), CHARINDEX(',', REPLACE(DateString, ' ', '')) + 1, LEN(REPLACE(DateString, ' ', '')) - CHARINDEX(',', REPLACE(DateString, ' ', '')) - 5)),2)
        ,'-'
        ,RIGHT(CONCAT('00',SUBSTRING(REPLACE(DateString, ' ', ''), 1, CHARINDEX(',', REPLACE(DateString, ' ', '')) - 1)),2)
        ) 

SELECT ID,DateString,DateColumn
FROM @Table
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.