2012-01-19 2 views
1

ASP.Net Webサイトでいくつかのコードをリファクタリングしようとしていますが、私が書いているストアドプロシージャに問題があります。日付範囲内のテーブルからすべての日付を選択し、空の日付に1行を含める

私がしたいのは、日付範囲を取得し、その範囲内のすべてのデータをテーブルから選択することですが、日付が存在しない場合でも行を選択する必要があります。

私の考えは、以下のコードでは、一時的なテーブルを作成し、日付範囲内のすべての日付を入力してから、これを選択しているテーブルに追加します。私はここで何か間違っていますか?この結合では、tempDateカラムは常にnullですが、テーブルをチェックして、そこにデータが入っています。

-- Parameters 
DECLARE @DutyDate datetime='2012-01-01 00:00:00' 
DECLARE @InstructorID nvarchar(2) = N'29' 

DECLARE @datesTBL TABLE (tempDate DATETIME) 

-- Variables 
DECLARE @StartDate DATETIME 
DECLARE @EndDate DATETIME 

SELECT 
    @StartDate =StartDate, 
    @EndDate = EndDate 
FROM 
    DutyPeriodTbl 
WHERE 
(StartDate <= @DutyDate) 
AND 
(EndDate >= @DutyDate) 


DECLARE @d DATETIME = @StartDate 
WHILE @d<[email protected] 
BEGIN 
    INSERT INTO @datesTBL VALUES (CONVERT(DATETIME, @d, 102)) 
    SET @d=DATEADD(day,1,@d) 
END 

SELECT 
    dt.tempDate , 
    InstructorID,   EventStart, 
    EventEnd,    cancelled, 
    cancelledInstructor, 
    EventType,    DevName, 
    Room,     SimLocation, 
    ClassLocation,   Event, 
    Duration,    TrainingDesc, 
    Crew,     Notes, 
    LastAmended,   InstLastAmended, 
    ChangeAcknowledged,  Type, 
    OtherType,    OtherTypeDesc, 
    CourseType 
FROM 
    OpsInstructorEventsView iv 
LEFT OUTER JOIN 
    @datesTBL dt 
ON 
    CONVERT(DATETIME, iv.EventStart, 102) = CONVERT(DATETIME, dt.tempDate, 102) 
WHERE 
    InstructorID = @InstructorID 
AND 
    EventStart BETWEEN CONVERT(DATETIME, @StartDate, 102) AND CONVERT(DATETIME, @EndDate, 102) 
ORDER BY 
    EventStart 
+0

CTEは、これを行うことができ、http://stackoverflow.com/questions/5899829/sqlを見てみましょう-server-how-to-select-all-days-in-date-range-to-no-data-exists-for-so –

答えて

3

が不足している行を扱うにはいくつかの方法がありますが、すべてはあなたの現在の結果と結合するために、データの別のセットを持っていることについてです。

CTEや他のプロセス(例のような)によって作成された結果、または永久的なテンプレートを使用して作成された結果は、結果として得られます。

あなたの場合のテンプレートは、あなたの@datesTBLのように、日付のテーブルにすることができます。違いは、例えば100年分の日付で事前に作成されていることです。

あなたのクエリは、次にあなたの例と同様とすることができるが、私は次のことをしようと...

SELECT 
    dt.tempDate , 
    InstructorID,   EventStart, 
    EventEnd,    cancelled, 
    cancelledInstructor, 
    EventType,    DevName, 
    Room,     SimLocation, 
    ClassLocation,   Event, 
    Duration,    TrainingDesc, 
    Crew,     Notes, 
    LastAmended,   InstLastAmended, 
    ChangeAcknowledged,  Type, 
    OtherType,    OtherTypeDesc, 
    CourseType 
FROM 
    @datesTBL dt 
LEFT OUTER JOIN 
    OpsInstructorEventsView iv 
    ON iv.EventStart >= dt.tempDate 
    AND iv.EventStart < dt.tempDate + 1 
    AND iv.InstructorID = @InstructorID 
WHERE 
     dt.tempDate >= @StartDate 
    AND dt.tempDate <= @EndDate 
ORDER BY 
    dt.tempDate, 
    iv.EventStart 

これはLEFTにカレンダーテンプレートを置き、そしてあなたが知っているように、多くのクエリが容易になりますカレンダーの日付フィールドは常に入力され、常に日付のみ(時間部分はありません)値です。GROUP BYなどに簡単です。

+0

+1: 'カレンダー'テーブルは簡単に行く方法です人口が豊富で常に有用です。他の方法でそれらを使用するためのヒントやヒントについては、Googleの「celkoカレンダーテーブル」を参照してください。 – Tony

+0

これで完全に解決されたので、カレンダーテーブルも使用します。情報をありがとう – Purplegoldfish

0

まあ、アイデアは同じですが、私は関数を書くでしょう期間内のすべての日付を含むテーブルを返します。これを見て:

Create Function [dbo].[Interval] 
(
    @DateFrom Date, 
    @DateTo Date 
) 
Returns @tab Table 
    (
     MyDate DateTime 
    ) 
As 
Begin 
    Declare @Days int 
    Declare @i int 
    Set @Days = DateDiff(Day, @DateFrom, @DateTo) 

    Set @i = 0; 
    While (@Days > @i) 
    Begin 
     Insert Into @tab(MyDate) 
      Values (DateAdd(Day, @i, @DateTo)) 
     Set @i = @i + 1 
    End 
    return 
End 

そして、あなたがそれを必要なときに機能を再利用...

Select * 
From [dbo].[Interval]('2011-01-01', GETDATE()) 
関連する問題