SQL OUTER JOIN返回一些空记录 - 为什么?

时间:2017-02-09 19:19:03

标签: sql sql-server join outer-join

我有一个表project p和一个表invoice i,两者都有一个project_id字段。我想要一个结果集,其中包含来自project i.status = "Active"的所有project_ids,其中还包括来自invoice invoice_date > 2016-01-01的所有project_ids。这是我到目前为止所尝试的查询。

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-01-01开具发票。上面的查询返回大约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...

2 个答案:

答案 0 :(得分: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 distinct表中可能需要invoice

答案 1 :(得分:2)

更改为

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

,您将不会有任何空值。空值是发票中的值,但不是项目。