2011-09-07 44 views
13

Trong SQL Server 2008, isoweek thể được tìm thấy với điều này:Isoweek trong SQL Server 2005

SELECT datepart(iso_week, getdate()) 

Trước khi SQL Server 2008 không có tích hợp chức năng để tìm isoweek.

Tôi đã tìm kiếm cao và thấp cho một cú pháp tốt để tìm một useroefined iso_week cho SQL Server 2005. Tôi tìm thấy một vài giải pháp. Không thích bất kỳ giải pháp nào tôi tìm thấy, hầu hết chúng không hoạt động, và chúng quá dài.

Vì vấn đề này rất cũ, tôi cho rằng vấn đề này đã cạn và giải pháp tốt nhất đã được tìm thấy. Tôi đã không thể tìm thấy một phương pháp tốt mặc dù.

Tôi đã viết một giải pháp, mà tôi sẽ đăng sau. Nhưng trước khi tôi làm, tôi muốn chắc chắn rằng không ai khác có thể phù hợp với giải pháp mà tôi đã viết.

Tôi hy vọng sẽ giành được huy hiệu tự học. Tôi thúc giục mọi người tìm ra câu trả lời tốt nhất cho câu hỏi cổ này.

Tôi sẽ đăng câu trả lời của mình sau khi cho mọi người cơ hội tìm được giải pháp tốt.

+0

Cùng với số tuần, điều quan trọng là phải bao gồm năm trong tuần ISO, vì nó có thể khác với năm ngày bình thường. Điều đó dường như không tầm thường. –

+0

@MicheldeRuiter liên kết đến iso_year [ở đây] (http://stackoverflow.com/questions/22829604/what-is-iso-year-in-sql-server/22830524#22830524) –

+0

Tôi đã tìm thấy câu trả lời của bạn ở đó, tốt để làm cho người đọc khác biết. –

Trả lời

12

Đây là một cách tiếp cận tương tự như cách bạn làm ở chỗ nó cũng dựa vào thứ Năm tuần này. Nhưng cuối cùng nó sử dụng ngày khác nhau.

  1. Lấy ngày thứ năm (ISO) của tuần này.

    Giải pháp của riêng bạn sử dụng ngày được mã hóa cứng của Thứ Năm đã biết. Ngoài ra, hôm thứ Năm tuần này có thể được tìm thấy với sự giúp đỡ của @@DATEFIRST:

    SELECT Th = DATEADD(DAY, 3 - (DATEPART(WEEKDAY, @date) + @@DATEFIRST - 2) % 7, @date) 
    

    (. Tôi đã không gặp khó khăn quá nhiều cho công thức đúng vì nó là already known với tôi)

  2. Nhận ngày hôm thứ Năm năm:

    SELECT DY = DATEPART(DAYOFYEAR, Th) 
    
  3. Sử dụng số để tìm ra tuần như thế này:

    SELECT ISOWeek = (DY - 1)/7 + 1 
    

Sau đây là các tính toán ở trên trong một tuyên bố duy nhất:

SELECT ISOWeek = (DATEPART(DAYOFYEAR, Th) - 1)/7 + 1 
FROM (
    SELECT Th = DATEADD(DAY, 3 - (DATEPART(WEEKDAY, @date) + @@DATEFIRST - 2) % 7, @date) 
) s; 
+0

+1 awsome, đã cho tôi một thời gian để nhận ra những gì bạn đang làm, cho đến nay tôi quyết định bạn đang gian lận, tại sao tôi không nghĩ về điều đó. Tôi kết hợp câu trả lời của chúng tôi với một giải pháp nhỏ gọn rất ngắn. –

+0

Bạn thực sự xứng đáng nhận được tín dụng cho giải pháp này, người bạn đời tốt. –

+0

Cảm ơn bạn rất nhiều! –

34

Có một liên kết vào đây để nỗ lực trước đây khác http://www.sqlteam.com/forums/topic.asp?TOPIC_ID=60510

Đây là mã OLD cho hàm

CREATE function f_isoweek(@date datetime) 
RETURNS INT 
as 
BEGIN 
DECLARE @rv int 

SELECT @rv = datediff(ww, dateadd(ww, datediff(d, 0, dateadd(yy, datediff(yy, 0, day4),3))/7,-4),day4) 
FROM (SELECT dateadd(ww, datediff(day, 0, @date)/7, 3) day4) a 

RETURN @rv 
END 

Sau khi kết hợp câu trả lời tuyệt vời @AndriyM 's với riêng tôi, chúng tôi đang xuống đến 1 hàng. Đây là mã MỚI.

CREATE function f_isoweek(@date datetime) 
RETURNS INT 
as 
BEGIN 

RETURN (datepart(DY, datediff(d, 0, @date)/7 * 7 + 3)+6)/7 
-- replaced code for yet another improvement. 
--RETURN (datepart(DY, dateadd(ww, datediff(d, 0, @date)/7, 3))+6)/7 

END 

Giải thích cho mã cũ (sẽ không giải thích mã mới Đó là mảnh vỡ từ mã của tôi và mã AndriyM của.):

Tìm trong tuần 4 của ngày đã chọn

dateadd(week, datediff(day, 0, @date)/7, 3) 

Tìm kiếm isoyear - năm của các ngày trong tuần 4 của một tuần luôn luôn là cùng năm như isoyear của tuần đó

datediff(yy, 0, day4) 

Khi thêm 3 ngày cho đến ngày đầu tiên của isoyear một ngày ngẫu nhiên của các isoweek đầu tiên của isoyear được tìm thấy

dateadd(yy, datediff(yy, 0, day4),3) 

tìm tuần tương đối của isoweek đầu tiên của isoyear

datediff(d, 0, dateadd(yy, datediff(yy, 0, day4),3))/7 

Tìm kiếm thứ hai trừ đi 4 ngày kể từ khi kết quả isoweek đầu tiên trong thứ năm trong tuần trước ngày đầu tiên của isoweek đầu tiên của isoyear

dateadd(ww, datediff(d, 0, dateadd(yy, datediff(yy, 0, day4),3))/7,-4) 

Biết thứ năm đầu tiên của t tuần trước khi isoweek đầu tiên và thứ năm đầu tiên của tuần được chọn, làm cho nó là khá dễ dàng để tính toán trong tuần, nó không quan trọng mà thiết lập datefirst có kể từ các ngày trong tuần của cả hai ngày là thứ năm.

datediff(ww, dateadd(ww, datediff(d, 0, dateadd(yy, datediff(yy, 0, day4),3))/7,-4),day4) 
+0

+1. So với phiên bản này http://msdn.microsoft.com/en-us/library/ms186755.aspx của bạn là nhiều hơn vì nó không phụ thuộc vào 'set datefirst 1'. –

+0

Tuyệt vời! Và tôi thích '(n + 6)/7' tốt hơn' (n - 1)/7 + 1' của tôi. Sẽ có upvoted này một lần nữa, nếu tôi có thể. –

+0

+1000 Giảm công thức tuyệt vời. –

1

Wow! Chủ đề và giải pháp rất tốt để tránh sử dụng "set datefirst 1". Tôi chỉ muốn thêm một cái gì đó. Nếu như tôi, bạn cũng muốn trả lại năm với tuần ISO, như "2015-01" là "Năm 2015, Tuần lễ 01", điều này có thể hữu ích cho mục đích báo cáo. Vì năm từ tuần ISO có thể khác so với năm thực tế của ngày! Đây là cách tôi đã kết hợp với mã của bạn.

DECLARE @Date AS DATETIME 
SET @Date = '2014-12-31' 
SELECT 
     CAST(CASE WHEN MONTH(@Date) = 1 AND Q.ISOweek > 50 THEN YEAR(@Date) - 1 
       WHEN MONTH(@Date) = 12 AND Q.ISOweek < 3 THEN YEAR(@Date) + 1 
       ELSE YEAR(@Date) 
      END 
      AS VARCHAR(4)) 
    + '-' 
    + RIGHT('00' + CAST(Q.ISOweek AS NVARCHAR(2)), 2) AS ISOweek 
FROM (SELECT (datepart(DY, datediff(d, 0, @Date)/7 * 7 + 3) + 6)/7 AS ISOweek) Q 

Sẽ trả lại "2015-01".

+1

Tôi đã viết một kịch bản đơn giản cho iso_year. http://stackoverflow.com/questions/22829604/what-is-iso-year-in-sql-server/22830524#22830524 –

0

Tôi cần một cái gì đó tương tự cho PowerQuery & PowerBI và dựa trên phản hồi của t-clausen.dk tôi đã có thể thực hiện phương trình này. Nó hoạt động giống như của anh ta nhưng sử dụng cú pháp PowerQuery. Cũng là ngày cơ sở cho DATEDIFF 0 là 1900/01/01 trong SQL nhưng trong PowerQuery nó là 1899/12/30 vì vậy tôi sử dụng 2 thay vì 0.

ISO Week = Number.RoundDown((Date.DayOfYear(Date.From(Duration.Days(([Date]-Date.From(2))/7)*7+5))+6)/7) 

tôi cũng cần năm ISO để Tôi đã thực hiện điều chỉnh đối với tính toán Tuần ISO và đã đưa ra:

ISO Year = Date.Year(Date.From(Duration.Days(([Date]-Date.From(2))/7)*7+3)) 

Thay đổi [Date] để tham chiếu cột ngày trong dữ liệu.

Các vấn đề liên quan