2011-12-14 9 views
0

私はこのようなタイムクロック情報を含むSQLテーブルを持っています。特定の日付に従業員が働いていた分数。テーブルは数年間の価値がありますが、土曜日と日曜日、および休日以外の日/休日が不足しています(時折の例外を含む)。1か月に日付を列としてピボットします。動的SQLなしで可能ですか?

EmployeeID Date Attended Total Minutes 
----------------------------------- 
001   '11/01/2011' 319 
002   '11/01/2011' 355 
003   '11/01/2011' 352 
001   '11/02/2011' 340 
002   '11/02/2011' 322 
003   '11/02/2011' 351 

このようなデータを、指定された月の出席を要約したレポートに表示するピボットを作成する必要があります。

EmployeeId '11/01/2011' '11/02/2011' .... (for all dates in a month) 
----------------------------------------------------------------------- 
001   319   340 
002   355   322 
003   352   351 

私は機能するソリューションを持っている(下記参照)... が、私のアプローチは、特定の月の日からピボットステートメントを構築するために動的SQLを使用しています。私の心の後ろには、動的SQLを使用しない方法がなければならないと思っていますが、それは私には当てはまりません。任意の提案... 私は動的SQLに立ち往生ですか?

DECLARE @columns VARCHAR(8000) 
DECLARE @headers VARCHAR(8000) 
DECLARE @lowdate Date 
DECLARE @highdate Date 

SELECT @columns = COALESCE(@columns + ',[' + cast(Attended as varchar) + ']', 
        '[' + cast(Attended as varchar)+ ']') 
FROM TimeAttended WHERE attended >= @date and attended <= @highdate 
GROUP BY Attended 

SELECT @headers = COALESCE(@Headers + ',Sum([' + cast(Attended as varchar) + ']) as [' + cast(Attended as varchar) + ']', 
        'Sum([' + cast(Attended as varchar)+ ']) as [' + cast(Attended as varchar) + ']') 
FROM TimeAttended WHERE attended >= @date and attended <= @highdate 
GROUP BY Attended 

DECLARE @query VARCHAR(8000) 
SET @query = ' 
SELECT employeeid, ' + @headers + ' 
FROM TimeAttended 
PIVOT 
(
Sum(TotalMinutes) 
FOR [Attended] 
IN (' + @columns + ') 
) 
AS p group by employeeid' 

EXECUTE(@query) 

答えて

1

動的SQLを使用する明白な方法の1つ(私が一般的に可能な場合は避ける方が一般的です)に加えて、2つの静的オプションがあります。

最初は、通常通り行を取得してから、結果を表示コードでピボットすることです(これは、関係なく行っています)。これは何らかの種類のレポートを生成し、必要な処理能力を利用できると仮定しています。

2番目の方法では、データについて若干異なる考え方が必要です。
の特定のの日付セットを表示するためのステートメントを作成する代わりに、特定の日付から最後の31日間のセットを参照するようにコーディングします。その後、

SELECT a.Id, COALESCE(b.Minutes, 0), COALESCE(c.Minutes, 0), (etc) 
FROM Employees as a 
LEFT JOIN TimeClock as b 
ON b.EmployeeId = a.id 
AND b.Date = @Given 
LEFT JOIN TimeClock as c 
ON C.EmployeeId = a.Id 
AND c.Date = DATEADD(DAY, 1, @Given) 
(etc) 

...そして、表示テーブルなどのCOLUMN1に結果のcolumn1のにマッピング:1日など -
ある は、COLUMN2が指定した日付で、COLUMN3は​​、与えられた日付です

+0

これは興味深いオプションです...私はそれにいくつかの脳の力を投げ、あなたに戻ってくるつもりです。 – RThomas

+0

これは機能します...私は受け入れる前に私が既にそれをやっている方法と比較して、それがどう動くかを見るためにいくつかのテストを行いますが、+動的なSQLを使用しない創造的なアプローチを私に与える+1。 – RThomas

+0

複数の結合アプローチが勝ちます。レポートサービスのレポートを作成し始めた後、動的な方法でレポートの列をマッピングできなくなったことがわかりました。代わりに1 - 31という名前を付けることで、自分のrdlc内の関数を使用して、自分の日付に基づいて実際の日付を追加する列に名前を付けることができます。再度、感謝します。 – RThomas

0

あなたはあなたが列ヘッダーに値をもとにしたい場合は、動的SQLを使用する必要が事前に値がわかっている場合を除き。

これを行うことができる唯一のデータベースはMS Accessのは、出力の各ビットはちょうど一ヶ月に属しているために起こっている場合、あなたは1からにすべての日ハードコードでき
、ダイナミックSQLから離れて

+0

これは私が恐れていたものです。私はまったくそれを避けることができます動的SQLを好きではありません。 – RThomas

1

を変換であります31:

with data as (
    select * 
    from (
    values 
    (001,   '20111101', 319), 
    (002,   '20111101', 355), 
    (003,   '20111101', 352), 
    (001,   '20111102', 340), 
    (002,   '20111102', 322), 
    (003,   '20111102', 351) 
) foo (EmployeeID, [Date], [Minutes]) 
), 
prepared_data as (
    select EmployeeID, [Minutes], day([date]) as [day] 
    from data 
) 
select * 
from 
    prepared_data 
    pivot (min([Minutes]) for [day] in ([1],[2],[3],[4],[5],[6],[7],[8],[9],[10],[11],[12],[13],[14],[15],[16],[17],[18],[19],[20],[21],[22],[23],[24],[25],[26],[27],[28],[29],[30],[31])) pvt 
; 

そして後の段階の皮でのみnull秒を持っている他の方法の列に無視。

関連する問題