2011-07-19 2 views
1

私はT-SQL(MSSQL 2005)で行うことはかなり難しい作業です。私はこのようなテーブルを持っています:T-SQLタスク - 2つの日付範囲に指定された曜日を持つすべての日付を検索

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

ここで、第1列はWeekDay番号で第2列はTime値です。私は、例えば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 tclausen、私もそれをテストします! – binball

+0

SQL Server 2008で導入され、OPがSQL Server 2005を使用しているため、time型が使用されていない可能性があります。 –

+0

@ t-clausen、時間値'13:00 'の結果は' date 12:59 :59.997 '代わりに' date 13:00:00 ' – binball

1

数字表と呼ばれるものを使用できます。あなたの日付の間にある日数と同じ数の行のテーブルを作成し、順番に番号を付けてください。ここで

は、SQL 2008での番号表を作成するためのかなり滑らかな方法です、また、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に同意しますFoxはその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 
関連する問題