1つのテーブルに存在しない行を含む行を表示するSQL結合クエリ


12

私は従業員の時間記録についていくつかのレポートを作成しようとしています。

この質問に特化した2つの表があります。従業員はMembersテーブルに一覧表示され、毎日、彼らが実行した作業の時間エントリを入力し、Time_Entryテーブルに保存されます。

SQL Fiddleでの設定例:http ://sqlfiddle.com/#!3/ e3806/7

私は行くよ最終結果は番組表であるALLMembers列リストで、その後は他の列に照会した日のために彼らの合計時間が表示されます。

問題はTime_Entry、特定のメンバーのテーブルに行がない場合、そのメンバーの行があることです。私はいくつかの異なる結合タイプ(左、右、内部、外部、完全外部など)を試しましたが、(SQL Fiddleの最後の例に基づいて)希望どおりの結果が得られないようです。

/*** Desired End Result ***/

Member_ID   | COUNTTime_Entry | TIMEENTRYDATE | SUMHOURS_ACTUAL | SUMHOURS_BILL
ADavis      | 0               | 11-10-2013    | 0               | 0
BTronton    | 0               | 11-10-2013    | 0               | 0
CJones      | 0               | 11-10-2013    | 0               | 0
DSmith      | 0               | 11-10-2013    | 0               | 0
EGirsch     | 1               | 11-10-2013    | 0.92            | 1
FRowden     | 0               | 11-10-2013    | 0               | 0

11-1の特定の日付をクエリしたときに私が現在得ているもの:

Member_ID   | COUNTTime_Entry | TIMEENTRYDATE | SUMHOURS_ACTUAL | SUMHOURS_BILL
EGirsch     | 1               | 11-10-2013    | 0.92            | 1

これは、EGirschの2013年11月10日付けの1つのタイムエントリ行に基づいて正しいですが、レポートを取得し、最終的にこの情報のWebダッシュボード/レポートを取得するには、他のメンバーのゼロを表示する必要があります。

これは私の最初の質問です。Joinクエリなどを検索しましたが、正直に言って、この関数が何と呼ばれるかわからないので、これが重複しておらず、解決策を見つけようとしている他の人にも役立つことを願っています同様の問題。

回答:


11

SQLfiddleとサンプルデータをありがとう!もっと多くの質問がこのように始まって欲しいです。

その日付のエントリがあるかどうかに関係なく、すべてのメンバーが必要な場合は、が必要ですLEFT OUTER JOINこのバージョンに非常に近かったですが、外部結合の小さなトリックは、WHERE句の外部テーブルにフィルターを追加すると、外部結合を内部結合に変換することです。これNULLにより、その側にある行がすべて除外されます。(NULLフィルターと一致するかどうかがわからないため)。

最初のクエリを変更して、すべてのメンバーの行を取得します。

SELECT Members.Member_ID
      ,Time_Entry.Date_Start
      ,Time_Entry.Hours_Actual
      ,Time_Entry.Hours_Bill
FROM dbo.Members
  LEFT OUTER JOIN dbo.Time_Entry
--^^^^ changed from FULL to LEFT
  ON Members.Member_ID = Time_Entry.Member_ID
  AND Time_Entry.Date_Start = '20131110';
--^^^ changed from WHERE to AND

読者がそこから取り出して、他の列やフォーマットCOALESCEなどを追加するための演習として残しておきます。

その他の注意事項:


アーロン、フィードバックに感謝します。SQLここでは初心者、とは考えとの違いはなかったWHEREとしますAND。私は元々エイリアスを使用していましたが、sqlfiddleはそれを気に入らなかったので、完全な形式にしました。他のSQLのヒントもありがとうございます。あなたは勧めISNULLまたはCOALESCEデータにするために0の代わりにNULL?再度、感謝します!
farewelldave

1
@farewelldave COALESCEは標準であり、他の言語の機能から逸脱していないため、私はCOALESCEを好みます(たとえば、ISNULLがSQL ServerとVBでどのように機能するかを比較してください)。1つを除いて、ほとんどすべての場合、パフォーマンスの違いは重要ではありません。詳細はこちら
アーロンバートランド

4

過去にこの種の問題に直面したことがある場合は、不足している行の処理に役立つ「数値」テーブルを作成しました。

私は特に日付を処理するために数値テーブルを作成しました:

CREATE TABLE Dates
(
    dDate DATETIME NOT NULL CONSTRAINT PK_Dates PRIMARY KEY CLUSTERED
);

INSERT INTO Dates (dDate)
SELECT TOP(73049) DATEADD(d, -1, ROW_NUMBER() OVER (ORDER BY o.object_id)) AS dDate
FROM master.sys.objects o, master.sys.objects o1, master.sys.objects o2

これにより、1900-01-01から2099-12-31までの日付ごとに1行の表が作成されます。TOP(73049)私の例で生成される日付範囲をこれらの日付に制限するために使用しています-別の日付範囲で作業している場合は、その数値を調整できます。

次に、dDatesテーブルをクエリに追加して、各の目的の範囲のすべての日付の行が返されるようにしますmember_id。次に、結果がTime_Entryテーブルに結合されます。

SELECT MD.Member_ID,
    MD.dDate,
    T.Date_Start,
    T.Hours_Actual,
    T.Hours_Bill
FROM 
    (
        SELECT M.Member_ID, D.dDate
        FROM dbo.Dates D, dbo.Members M
        WHERE D.dDate >= '20131110' AND D.dDate < '20131112'
    ) AS MD
    LEFT JOIN dbo.Time_Entry T ON MD.Member_ID = T.Member_ID AND MD.dDate = T.Date_Start
ORDER BY MD.Member_ID, MD.dDate

これにより、レポートの日付範囲を指定できます。

あなたは、さらに追加して結果を絞り込むことができますCOALESCE(...)し、SUM(...)通り:

SELECT MD.Member_ID,
    MD.dDate,
    T.Date_Start,
    SUM(COALESCE(T.Hours_Actual, 0)) AS TotalHoursActual,
    SUM(COALESCE(T.Hours_Bill, 0)) AS TotalHoursBill
FROM 
    (
        SELECT M.Member_ID, D.dDate
        FROM dbo.Dates D, dbo.Members M
        WHERE D.dDate >= '20131110' AND D.dDate < '20131112'
    ) AS MD
    LEFT JOIN dbo.Time_Entry T ON MD.Member_ID = T.Member_ID AND MD.dDate = T.Date_Start
GROUP BY MD.Member_ID, MD.dDate, T.Date_Start
ORDER BY MD.Member_ID, MD.dDate

これにより、サンプルデータの出力は次のようになります。

ここに画像の説明を入力してください


ありがとう、マックス。「numbers table」の代わりに「tally table」を検索すると、この手法に関する多くの情報を見つけることができます。カーソル/ループを使用する操作をセットを使用する操作に変換することにより、パフォーマンスを向上させるのに最適です。リレーショナルデータベースはセットを優先します。
Suncat2000

1
@ Suncat2000-同意。ただし、集計は加算を意味するため、「数値テーブル」という名前を好むが、私の経験では、このパターンは数学演算にほとんど使用されない。これらは多くの点で優れていますが、確実に実現できる最大のパフォーマンス改善の1つは、数値表を使用することによるRBARアプローチからセットベースのアプローチへの移行です。
Max Vernon
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.