2017-02-09 7 views
0

私はテーブルproject pとテーブルinvoice iを持っています。どちらもproject_idフィールドを持っています。 projectのすべてのproject_idsを含む結果セットが必要です。ここではi.status = "Active"であり、それにはinvoiceのすべてのproject_idsが含まれます。invoice_date > 2016-01-01です。これまでに試した質問があります。SQL OUTER JOINが空のレコードを返す - なぜですか?

SELECT 
    p.project_id 
FROM 
    (SELECT project_id 
     FROM project 
     WHERE status = 'Active') p 
FULL OUTER JOIN 
    (SELECT DISTINCT project_id 
     FROM invoice 
     WHERE CONVERT(varchar(10),invoice_date, 20) > '2016-01-01') i 
ON i.project_id = p.project_id 

アクティブ状態とprojectsで約80プロジェクト=および2016年1月1日以来、請求されているinvoiceで約120のプロジェクトがあります。上記のクエリは約140のレコードを返します。これは正しいと思われるレコード(一部の請求対象外のアクティブなプロジェクトと非アクティブな請求対象のプロジェクト)です。問題は、クエリーのproject_idsの約半分が空(NULL?)であることです。これは、project_idsをinvoiceから引き出していないかのようです。これを修正するのを手伝ってください。ここで

は、配列として結果セットの短いセグメントは

SELECT coalesce(p.project_id, i.project_id) as project_id 

... 
[10] => Array 
    (
     [project_id] => 
    ) 

[11] => Array 
    (
     [project_id] => C00F2097-CD36-4497-8B26-0BF59F90B1EA 
    ) 

[12] => Array 
    (
     [project_id] => 217F3370-50F2-457E-A4F5-0C09F12E654A 
    ) 

[13] => Array 
    (
     [project_id] => 
    ) 

[14] => Array 
    (
     [project_id] => B1A06823-73C8-4691-A3D6-0E1A234516B3 
etc... 
+0

これらは 'アクティブな 'プロジェクトですが、' invoice_date>' 2016-01-01 'というインボイスから対応するプロジェクトがないためです。請求書のための「アクティブ」プロジェクトが存在しない場合があります。 – Lamak

+0

選択項目に両方のテーブルのプロジェクト値を含めます。私も文字列の値で "日付"を比較する理由は困惑している?私はyyyy-mm-dd形式なので動作すると思います。日付のデータ型を使って日付を比較するほうが安全だと思います。 – xQbert

答えて

2

変更...であり、あなたは、任意のnull値を持ちません。 null値は請求書のものですが、プロジェクトではありません。

+1

ゴードンの答えは良いですが、問題の内容を理解するのに役立ちます。 – Hogan

3

あなたの説明は「use UNION、use UNION」と叫んでいます!

SELECT p.project_id 
FROM project p 
WHERE p.status = 'Active' 
UNION -- On purpose to remove duplicates 
SELECT i.project_id 
FROM invoice i 
WHERE i.invoice_date > '2016-01-01'; 

注:定数を比較するために日付を文字列に変換する必要はありません。実際、それは良い考えではありません(インデックスの使用を妨げる)。

UNION ALLを使用してこれをフレーズすることもできます。これはおそらく、(テーブルが適切なインデックスを持っていると仮定して)あなたが欲しいものを得るための最も安価な方法である。この場合、

SELECT p.project_id 
FROM project p 
WHERE p.status = 'Active' 
UNION ALL 
SELECT i.project_id 
FROM invoice i 
WHERE invoice_date > '2016-01-01' AND 
     NOT EXISTS (SELECT 1 
        FROM project p2 
        WHERE p2.project_id = i.project_id AND p.status = 'Active' 
       ); 

プロジェクトは、複数のインデックスを持つことができれば、あなたはinvoiceテーブルにselect distinctが必要になる場合があります。

+0

私はあなたがここまでずっと叫んだことを聞いた。 – Hogan

+0

SQL Serverではリテラルが 'YYYYMMDD'(ダッシュなし)になっている必要があります。そのため、 '20160101'にする必要があります。 –

+0

@ThorstenKettner。 。 。 YYYYMMDDは、国際化の設定に関係なく明白であるため、技術的にはSQL Serverの日付定数に最適な形式です。私はYYYY-MM-DDが好きです。なぜなら、(1)ISO 8601にも準拠しているからです。 (2)私は人間である(逆の噂にもかかわらず)、読みやすい。 (3)多種多様なデータベースによるサポートです。 –

関連する問題