2011-07-19 162 views
1

對於我在T-SQL(MSSQL 2005)中執行的任務,我有相當艱鉅的任務。我有這樣的表格:T-SQL任務 - 在兩個日期範圍內查找指定星期幾的所有日期範圍

WeekDay| SlotTime 
------------------ 
| 1 | 07:00 
| 3 | 09:00 
| 7 | 14:00 
| 1 | 15:00 
| 4 | 22:00 
| 6 | 08:00 

其中第1列是週日數,第2列是某個時間值。

至於我的查詢參數我有兩個日期,例如:

StartDate = '2011-07-20' 
EndDate = '2011-08-17' 

這是我的數據的範圍定義。我必須爲這些範圍生成WeekDay(來自上表)發生的所有日期,並將它們添加到SlotTime值中。 因此,例如,對於上述日期範圍的結果列應該是:

2011-07-20 9:00 
2011-07-21 22:00 
2011-07-23 8:00 
2011-07-24 14:00 
2011-07-25 7:00 
2011-07-25 15:00 
2011-07-27 9:00 
2011-07-28 22:00 
2011-07-30 8:00 
etc. 
... 

任何想法如何實現這一目標?有小費嗎? :)我正在考慮這是相當不可能的,沒有一些巨大的(?)計算和附加表...

編輯(也許這個片段將有所幫助) 我正在玩這個函數來使用它作爲我的計算的一部分,但無法實現我的目標。也許有些部分可以用於最終的解決方案...

create function dbo.NthWeekDay(
    @first datetime, -- First of the month of interest (no time part) 
    @nth tinyint,  -- Which of them - 1st, 2nd, etc. 
    @dow tinyint  -- Day of week we want 
) returns datetime as begin 
-- Note: Returns a date in a later month if @nth is too large 
    declare @result datetime 
    set @result = @first + 7*(@nth-1) 
    return @result + (7 + @dow - datepart(weekday,@result))%7 
end 
go 

SET DATEFORMAT ymd 
SET DATEFIRST 1 

select dbo.NthWeekDay('2011-07-20',1,1) as D 

go 

drop function NthWeekDay 
+0

什麼定義1是什麼?週日,週一,週四? –

+0

對不起,這是星期一。 SET DATEFIRST 1 SET DATEFORMAT ymd – binball

+0

我現在想不到字符串,所以如果沒有人有明天就會留下答案。如果您想自己嘗試,則需要使用'DATEPART(dw,'')'。我認爲這不會像你想象的那麼複雜。 –

回答

1

這將這樣的伎倆

SET DATEFIRST 1 
-- temp table 
declare @t table(WeekDay tinyint, SlotTime time) 
-- fill table 
insert @t values (1, '7:00') 
insert @t values (3, '9:00') 
insert @t values (7, '14:00') 
insert @t values (1, '15:00') 
insert @t values (4, '22:00') 
insert @t values (6, '8:00') 

-- declare interval 
declare @startdate datetime 
declare @enddate datetime 
set @StartDate = '2011-07-20' 
set @EndDate = '2011-08-17' 

;with cte as 
(
-- recusive to make timeline 
SELECT @StartDate loopday 
UNION ALL 
SELECT loopday + 1 
FROM cte 
WHERE loopday < @EndDate 
), b as 
(
-- join timeline with Weekday and add Slottime to timeline 
SELECT loopday + t.SlotTime col 
FROM cte 
JOIN @t t 
ON t.WeekDay = datepart(weekday, cte.loopday) 
) 
SELECT col 
FROM b 
ORDER BY 1 
OPTION(MAXRECURSION 0) 

(結果看起來像你的輸出)

+0

thx t-clausen,我也會測試它! – binball

+0

你可能不應該使用'time'類型,因爲它是在SQL Server 2008中引入的,而且OP使用SQL Server 2005. –

+0

@ t-clausen,對於時間值'13:00',結果是'date 12:59 :59.997'而不是'日期13:00:00' – binball

1

您可以使用所謂的數字表。只需創建一個表格,其行數與日期之間的日期相同,然後按順序編號。

這裏是2008年的SQL創建一個數字表非常漂亮的方式,在2005年也可能工作: http://archive.msdn.microsoft.com/SQLExamples/Wiki/View.aspx?title=NumbersTable

或者,您只需創建一個表的身份,然後插入TOP x行了進去。

從那裏,你可以計算出其餘

number 
1   DateAdd(dd, '2011/07/20', number)  DatePart(dw, DateAdd(dd, '2011/07/20', number)) 
2   DateAdd(dd, '2011/07/20', number)  DatePart(dw, DateAdd(dd, '2011/07/20', number)) 
3   DateAdd(dd, '2011/07/20', number)  DatePart(dw, DateAdd(dd, '2011/07/20', number)) 
4   DateAdd(dd, '2011/07/20', number)  DatePart(dw, DateAdd(dd, '2011/07/20', number)) 
5   DateAdd(dd, '2011/07/20', number)  DatePart(dw, DateAdd(dd, '2011/07/20', number)) 
6   DateAdd(dd, '2011/07/20', number)  DatePart(dw, DateAdd(dd, '2011/07/20', number)) 
7   DateAdd(dd, '2011/07/20', number)  DatePart(dw, DateAdd(dd, '2011/07/20', number)) 

加入該表到原來的結果,然後將產品放入您的決賽桌。

查詢:

SELECT TOP 5000 
    IDENTITY(INT, 0, 1) AS N 
INTO 
    Number 
FROM 
    sys.objects a, 
    sys.objects b, 
    sys.objects c 

SELECT 
    N, 
    DATEADD(dd, N, '7/20/2011') AS Date, 
    DATEPART(dw, DATEADD(dd, N, '7/20/2011')) AS DayofWeek 
FROM 
    Number 
WHERE 
    DATEADD(dd, N, '7/20/2011') BETWEEN '7/20/2011' 
           AND  '8/17/2011' 

結果:

N   Date     DayofWeek 
----------- ----------------------- ----------- 
0   2011-07-20 00:00:00.000 4 
1   2011-07-21 00:00:00.000 5 
2   2011-07-22 00:00:00.000 6 
3   2011-07-23 00:00:00.000 7 
4   2011-07-24 00:00:00.000 1 
5   2011-07-25 00:00:00.000 2 
6   2011-07-26 00:00:00.000 3 
7   2011-07-27 00:00:00.000 4 
8   2011-07-28 00:00:00.000 5 
9   2011-07-29 00:00:00.000 6 
10   2011-07-30 00:00:00.000 7 
11   2011-07-31 00:00:00.000 1 
12   2011-08-01 00:00:00.000 2 
13   2011-08-02 00:00:00.000 3 
14   2011-08-03 00:00:00.000 4 
15   2011-08-04 00:00:00.000 5 
16   2011-08-05 00:00:00.000 6 
17   2011-08-06 00:00:00.000 7 
18   2011-08-07 00:00:00.000 1 
19   2011-08-08 00:00:00.000 2 
20   2011-08-09 00:00:00.000 3 
21   2011-08-10 00:00:00.000 4 
22   2011-08-11 00:00:00.000 5 
23   2011-08-12 00:00:00.000 6 
24   2011-08-13 00:00:00.000 7 
25   2011-08-14 00:00:00.000 1 
26   2011-08-15 00:00:00.000 2 
27   2011-08-16 00:00:00.000 3 
28   2011-08-17 00:00:00.000 4 
+0

嗨朗訊,thx的查詢,它解釋了我很多!看起來很有前途(確實如同解決方案;))我會測試它並讓你知道,THX很多! – binball

+0

將它標記爲答案,如果它解決了我^ _^ –

+0

我最渴望沒有選擇一個答案馬上。 30分鐘決定最佳SQL並不公平。讓它啜飲半天。然後回來選擇最好的解決方案。 –

0

我@Lucent同意福克斯那一個number table在這裏可以非常方便。但是,如果您要求的範圍不能超過5年半,則不必創建它。系統表稱爲master..spt_values,或者更準確地說,它的子集,其中type = 'P',可以在查詢中被用作數字表:

WITH datelist AS (
    SELECT 
    Date = DATEADD(DAY, number, @StartDate) 
    FROM master..spt_values 
    WHERE type = 'P' 
    AND number BETWEEN 0 AND DATEDIFF(DAY, @StartDate, @EndDate) 
) 
SELECT 
    Timestamp = d.Date + s.SlotTime 
FROM datelist d 
    INNER JOIN SlotTable s ON s.WeekDay = DATEPART(WEEKDAY, d.Date) 
ORDER BY Timestamp