6

次のようなデータのテーブルがあります。

Name    StartTime              FinishTime              Work
Bob     2010-08-03 08:00:00    2010-08-03 12:00:00     4
Bob     2010-08-03 13:00:00    2010-08-03 16:00:00     3
Pete    2010-08-04 08:00:00    2010-08-04 12:00:00     4
Mark    2010-08-04 10:00:00    2010-08-04 12:00:00     2

これらの日付範囲はいずれも、真夜中をまたぐことはできません。
入力の開始日が 2010-08-02 で終了日が 2010-08-05 の場合、次の出力が得られる SQL を作成したいと考えています。

Date          Name   TotalWork
2010-08-03    Bob    7
2010-08-03    Pete   3
2010-08-04    Pete   4
2010-08-04    Mark   2 

私は、おそらく次のような行として、関連する作業がない日も結果セットに表示する必要があります。

2010-08-05     NULL   0

他の言語と同じように SQL で日付を反復処理する方法がよくわかりません。

これに何らかのコンテキストを与えるために、この出力は最終的に Stacked Chart .Net コントロールに接続されます。

誰かが手がかり、チュートリアルへのリンク、またはその他のヘルプを教えてくれませんか? そうでなければ、私は何日もこれをいじることになると思います!

ありがとうございました!

ジョナサン

4

2 に答える 2

7

これを試して:

Select DateAdd(day, 0, DateDiff(day, 0, StartDate)) Date,
    Name, Sum (Work) TotalWork
From TableData
Group By Name, DateAdd(day, 0, DateDiff(day, 0, StartDate)) 

不足している日数を取得するのは困難です。

   Declare @SD DateTime, @ED DateTime  -- StartDate and EndDate variables
   Select @SD = DateAdd(day, 0, DateDiff(day, 0, Min(StartDate))),
          @ED = DateAdd(day, 0, DateDiff(day, 0, Max(StartDate)))
   From TableData
   Declare @Ds Table (aDate SmallDateTime)
   While @SD <= @ED Begin 
       Insert @Ds(aDate ) Values @SD
       Set @SD = @SD + 1
   End 
-- ----------------------------------------------------
 Select DateAdd(day, 0, DateDiff(day, 0, td.StartDate)) Date,
    td.Name, Sum (td.Work) TotalWork
 From @Ds ds Left Join TableData td
    On DateAdd(day, 0, DateDiff(day, 0, tD.StartDate)) = ds.aDate 
 Group By Name, DateAdd(day, 0, DateDiff(day, 0, tD.StartDate)) 

編集、共通テーブル式 (CTE) を使用するソリューションでこれを再検討しています。これには、日付テーブルを使用する必要はありません。

    Declare @SD DateTime, @ED DateTime
    Declare @count integer = datediff(day, @SD, @ED)
    With Ints(i) As
      (Select 0 Union All
    Select i + 1 From Ints
    Where i < @count )  
     Select DateAdd(day, 0, DateDiff(day, 0, td.StartDate)) Date,
         td.Name, Sum (td.Work) TotalWork
     From Ints i 
        Left Join TableData d
           On DateDiff(day, @SD, d.StartDate) = i.i
     Group By d.Name, DateAdd(day, 0, DateDiff(day, 0, d.StartDate)) 
于 2010-08-31T14:00:59.253 に答える
5

SQL で行を反復処理する方法は、そうしないことです。SQL はセットベースの言語であり、他の手続き型言語とはまったく異なる考え方が必要です。SQL を使用する場合、成功するためには、その考え方を変えることができる必要があります。

これをどのように処理するかは次のとおりです。

SELECT
    CONVERT(VARCHAR(10), StartTime, 121) AS [date],
    name,
    SUM(work)
FROM
    My_Table
WHERE
    StartTime >= @start_date AND
    StartTime < DATEADD(dy, 1, @finish_date)
GROUP BY
    CONVERT(VARCHAR(10), StartTime, 121),
    name

また、テーブルの設計は、通常のデータベース設計基準に違反しているように見えます。あなたの「作業」列は、実際には StartTime と FinishTime の間の単なる計算です。これにより、同じデータが複製され、あらゆる種類の問題が発生する可能性があります。たとえば、StartTime と FinishTime が 4 時間離れているのに、「Work」には 5 時間と表示されている場合はどうしますか?

作業が関連付けられていない日付を含めるには、フロント エンドで処理するか、「カレンダー」テーブルが必要です。そこにはすべての日付が含まれており、テーブルで LEFT JOIN を実行します。例えば:

SELECT
    CONVERT(VARCHAR(10), C.StartTime, 121) AS [date],
    MT.name,
    SUM(MT.work)
FROM
    Calendar C
LEFT JOIN My_Table MT ON
    MT.StartDate BETWEEN C.StartTime and C.FinishTime
WHERE
    C.StartTime >= @start_date AND
    C.StartTime < DATEADD(dy, 1, @finish_date)
GROUP BY
    CONVERT(VARCHAR(10), C.StartTime, 121),
    MT.name

カレンダー テーブルを使用すると、休日のフラグや「残業」日 (日曜日の勤務時間は 1.5 時間としてカウントされる場合があります) など、日付に追加情報を追加することもできます。

:Charles Bretanaのソリューションは、データ型を文字列に変換するのではなく、日時として保持するため、おそらく少しきれいです。他のコメントのいくつかについては、これをここに残しておきます。

于 2010-08-31T14:01:54.797 に答える