2017-02-09 33 views
0

我有一個表project p和表invoice i,它們都有一個project_id字段。我想要一個結果集,其中包含所有來自project的project_id,其中i.status = "Active"還包括來自invoice的所有project_id,其中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項目=活性和在invoice約120項目自2016年1月1日已被開具發票。上述查詢返回約140條記錄,這聽起來正確(一些非發票活動項目和一些非活動發票項目)。問題是查詢大約有一半的project_ids爲空(NULL?)。就好像它沒有從invoice中拉出project_ids。請幫我解決這個問題。

下面是結果設置爲陣列的短段...

... 
[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

因爲那些是'active'的項目,但沒有'invoice_date>'2016-01-01''的發票的相應項目。你可能會遇到這樣的情況:發票中沒有「活動」項目 – Lamak

+0

在你的選擇中包括兩個表項目值。我也很疑惑你爲什麼比較一個字符串值的「日期」?我想它會起作用,因爲它是yyyy-mm-dd格式;但對我來說使用日期數據類型比較日期似乎更安全。 – xQbert

回答

2

變化

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

,你不會有任何空值。空值是發票中的值,但不是項目。

+1

Gordan的回答比較好,但我會留下這個,希望它能幫助你理解問題所在。 – Hogan

3

你的描述只是喊「使用UNION,使用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' 
       ); 

在這種情況下,你可能需要select distinctinvoice表,如果一個項目可能有不止一個索引。

+0

我聽說你在這裏大喊大叫。 – Hogan

+0

我讀到日期字面值應該是'YYYYMMDD'在SQL Server中(沒有破折號),所以必須是'20160101'。 –

+0

@ThorstenKettner。 。 。 YYYYMMDD在技術上是SQL Server中日期常量的最佳形式,因爲無論國際化設置如何,它都是明確的。我更喜歡YYYY-MM-DD,因爲(1)它(也)符合ISO 8601; (2)我是一個人(儘管有相反的傳言),而且它更容易閱讀; (3)它得到各種數據庫的支持。 –