クロスタブ-同じ列に異なる日付(会議1、会議2、会議3など)を保存する
-
07-07-2019 - |
質問
異なる日付を追跡する必要があります(動的)。そのため、特定のタスクについて、X個の日付を追跡することができます(たとえば、DDR1会議日、DDR2会議日、期日など)。
私の戦略は、各日付の説明を保存する1つのテーブル(DateTypeID、DateDescription)を作成することでした。次に、メインテーブル(ID、TaskDescription、DateTypeID)を作成できます。したがって、すべての日付は1つの列に含まれ、TypeIDを調べることでその日付が何を表すかを知ることができます。問題は、グリッドに表示することです。クロス集計クエリを使用する必要があることは知っていますが、動作させることはできません。たとえば、SQL Server 2000でCaseステートメントを使用して、各列名が日付型の名前になるようにテーブルをピボットします。次の表がある場合:
DateTypeテーブル
DateTypeID |日付の説明
1 | DDR1
2 | DDR2
3 | DueDate
タスクテーブル
ID | TaskDescription
1 | Create Design
2 | Submit Paperwork
Tasks_DateTypeテーブル
TasksID | DateTypeID |日付
1 | 1 | 09/09/2009
1 | 2 | 10/10/2009
2 | 1 | 11/11/2009
2 | 3 | 12/12/2009
結果は次のようになります。
TaskDescription | DDr1 | DDR2 | DueDate
Create Design |09/09/2009 | 10/10/2009 | null
Submit Paperwork |11/11/2009 | null | 12/12/2009
誰も私がこれを研究する方法を知っているなら、感謝しています。日付ごとに列を作成する代わりにこれを行う理由は、ユーザーがテーブルに列を手動で追加してhtmlコードを編集することなく、将来ユーザーが必要なだけ日付を追加できるようにするためです。これにより、日付を比較したり、タイプ別に今後のタスクを表示したりするための簡単なコードも可能になります(例:「デザインのDDR1日付の作成」が近づいています)。
解決
これはあなたのデータでテストされた適切な答えです。最初の2つの日付タイプのみを使用しましたが、とにかくこれをすぐに作成します。
Select
Tasks.TaskDescription,
Min(Case DateType.DateDescription When 'DDR1' Then Tasks_DateType.Date End) As DDR1,
Min(Case DateType.DateDescription When 'DDR2' Then Tasks_DateType.Date End) As DDR2
From
Tasks_DateType
INNER JOIN Tasks ON Tasks_DateType.TaskID = Tasks.TaskID
INNER JOIN DateType ON Tasks_DateType.DateTypeID = DateType.DateTypeID
Group By
Tasks.TaskDescription
編集
vanは、日付のないタスクは表示されないことに言及しました。これは正しいです。左結合(再び、vanが言及)を使用してクエリを少し再構築すると、現時点では必要ではありませんが、すべてのタスクが返されます。
Select
Tasks.TaskDescription,
Min(Case DateType.DateDescription When 'DDR1' Then Tasks_DateType.Date End) As DDR1,
Min(Case DateType.DateDescription When 'DDR2' Then Tasks_DateType.Date End) As DDR2
From
Tasks
LEFT OUTER JOIN Tasks_DateType ON Tasks_DateType.TaskID = Tasks.TaskID
LEFT OUTER JOIN DateType ON Tasks_DateType.DateTypeID = DateType.DateTypeID
Group By
Tasks.TaskDescription
他のヒント
ピボットされた列が不明(動的)の場合、ms-sql 2000または2005のいずれかで手動でクエリを作成する必要があります。つまり、PIVOTなしで実行します。
これには、ストアドプロシージャ(通常はno-no)で動的SQLを実行するか、動的SQLでビューをクエリすることが含まれます。後者は私が一般的に行っているアプローチです。
ピボットについては、ここで説明するように、caseステートメントよりもRozenshteinメソッドの方が好きです。
http://www.stephenforte.net /PermaLink.aspx?guid=2b0532fc-4318-4ac0-a405-15d6d813eeb8
編集
linq-to-sqlでもこれを行うことができますが、かなり非効率的なコードを出力します(少なくともlinqpadで表示する場合)ので、お勧めしません。まだ興味があれば、その方法の例を投稿できます。
ピボット演算子の個人的な経験はありませんが、より良い解決策を提供できます。
しかし、私は過去にcase文を使用しました
SELECT
TaskDescription,
CASE(DateTypeID = 1, Tasks_DateType.Date) AS DDr1,
CASE(DateTypeID = 2, Tasks_DateType.Date) AS DDr2,
...
FROM Tasks
INNER JOIN Tasks_DateType ON Tasks.ID = Tasks_DateType.TasksID
INNER JOIN DateType ON Tasks_DateType.DateTypeID = DateType.DateTypeID
GROUP BY TaskDescription
これは機能しますが、タスクの説明が追加されるたびにSQLを変更する必要があるため、理想的ではありません。
編集:
PIVOTキーワードがSqlServer 2005に追加されたように見えます。この例は、 2000&の両方でピボットクエリを実行する2005、しかし、それは私の答えに似ています。
バージョン-1: + simple、-DateTypeが追加されるたびに変更する必要があります。したがって、動的なソリューションには適していません。
SELECT tt.ID,
tt.TaskDescription,
td1.Date AS DDR1,
td2.Date AS DDR2,
td3.Date AS DueDate
FROM Tasks tt
LEFT JOIN Tasks_DateType td1
ON td1.TasksID = tt.ID AND td1.DateTypeID = 1
LEFT JOIN Tasks_DateType td2
ON td2.TasksID = tt.ID AND td2.DateTypeID = 2
LEFT JOIN Tasks_DateType td3
ON td3.TasksID = tt.ID AND td3.DateTypeID = 3
バージョン2 :完全に動的です(いくつかの制限はありますが、処理できます-Googleで検索してください):
動的なピボットクエリの作成。 ダイナミッククロスタブ/ピボットテーブルを参照してください。 UDFのSPを1つ作成し、それを複数の目的に使用できます。これは元の投稿であり、多くのリンクと改善点を見つけることができます。
バージョン3 :クライアントコードが処理できるようにそのままにしておきます。動的なデータセットを返すようにSQLを設計するのではなく、クライアント(プレゼンテーションレイヤー)で処理します。クエリの結果として生じる動的な列を処理したくないので、正確にそれを推測する必要があります。 バージョン2 を使用する唯一の理由は、結果がレポートのテーブルとして直接表示される場合です。 真に動的なデータの他のすべてのケースでは、クライアントコードを使用します。たとえば、構造があり、フィールドDueDateが必須であるというロジックをどのように添付しますか。DB制約は使用できません。 DDR1がDDR2よりも高くないことをどのように確認しますか?これらがデータベース(CONSTRAINTSを使用できる場所)内の別個の(静的)列でない場合、クライアントコードはデータの整合性を検証します。
がんばって!