加入一个公共表,如何在另一个表上进行FULL OUTER JOIN扩展?

时间:2010-03-25 17:46:36

标签: sql join outer-join full-outer-join

我已经搜索了StackOverflow和Google以解决这个问题。

我正在尝试创建一个Microsot SQL Server 2008视图。不是存储过程。不是功能。只是一个查询(即一个视图)。

我有三张桌子。第一个表定义了一个公共密钥,比如说“CompanyID”。另外两个表有一个有时相同的字段,比如说“EmployeeName”。

我想要一个单独的表结果,当我的WHERE子句说“WHERE CompanyID = 12”时,如下所示:

CompanyID | TableA    | TableB
12        | John Doe  | John Doe
12        | Betty Sue | NULL
12        | NULL      | Billy Bob

我尝试了一个看起来像这样的FULL OUTER JOIN:

SELECT Company.CompanyID,
    TableA.EmployeeName,
    TableB.EmployeeName
FROM Company
FULL OUTER JOIN TableA ON Company.CompanyID = TableA.CompanyID
FULL OUTER JOIN TableB ON 
    Company.CompanyID = TableB.CompanyID AND 
    (TableA.EmployeeName IS NULL OR TableB.EmployeeName IS NULL OR TableB.EmployeeName = TableA.EmployeeName)

我只从一个匹配的表中获取NULL,我没有得到另一个表的扩展。在上面的示例中,我基本上只得到第一行和第三行而不是第二行。

有人可以帮我创建此查询并告诉我这是如何正确完成的吗?

BTW我已经有了一个非常干净的存储过程并填充了一个内存表,但这不是我想要的。

感谢。

- 编辑:

以下是目前没有工作的完整示例(它缺少'某人2'和'某人3'。

DECLARE @Company TABLE
(
    CompanyID int
)

INSERT INTO @Company (CompanyID) VALUES (10)
INSERT INTO @Company (CompanyID) VALUES (12)

DECLARE @TableA TABLE
(
    EmployeeId int,
    CompanyId int,
    EmployeeName varchar(30)
)

DECLARE @TableB TABLE
(
    EmployeeId int,
    CompanyId int,
    EmployeeName varchar(30)
)

INSERT INTO @TableA ( EmployeeId, CompanyId, EmployeeName )
VALUES ( 1, 10, 'someone' )

--INSERT INTO @TableA ( EmployeeId, CompanyId, EmployeeName )
--VALUES ( 2, 12, 'someone 2' )

INSERT INTO @TableA ( EmployeeId, CompanyId, EmployeeName )
VALUES ( 3, 12, 'someone 3' )

INSERT INTO @TableA ( EmployeeId, CompanyId, EmployeeName )
VALUES ( 3, 12, 'someone 4' )

INSERT INTO @TableB ( EmployeeId, CompanyId, EmployeeName )
VALUES ( 1, 10, 'someone' )

INSERT INTO @TableB ( EmployeeId, CompanyId, EmployeeName )
VALUES ( 2, 12, 'someone 2' )

--INSERT INTO @TableB ( EmployeeId, CompanyId, EmployeeName )
--VALUES ( 3, 12, 'someone 3' )

INSERT INTO @TableB ( EmployeeId, CompanyId, EmployeeName )
VALUES ( 3, 12, 'someone 4' )

SELECT Company.CompanyID,
    TableA.EmployeeName,
    TableB.EmployeeName
FROM @Company Company
FULL OUTER JOIN @TableA TableA ON Company.CompanyID = TableA.CompanyID
FULL OUTER JOIN @TableB TableB ON Company.CompanyID = TableB.CompanyID
WHERE
(
    TableA.EmployeeName IS NULL OR TableB.EmployeeName IS NULL OR 
    TableB.EmployeeName = TableA.EmployeeName
)
AND Company.CompanyID = 12

结果:

CompanyID   EmployeeName    EmployeeName
12          someone 4       someone 4

我想要的是什么:

CompanyID   EmployeeName    EmployeeName
12          NULL            someone 2
12          someone 3       NULL
12          someone 4       someone 4

4 个答案:

答案 0 :(得分:2)

试试这个:

SELECT Company.CompanyID,
    TableA.EmployeeName,
    TableB.EmployeeName
FROM Company
LEFT OUTER JOIN TableA ON Company.CompanyID = TableA.CompanyID
LEFT OUTER JOIN TableB ON Company.CompanyID = TableB.CompanyID
WHERE (TableA.EmployeeName IS NULL OR TableB.EmployeeName IS NULL OR TableB.EmployeeName = TableA.EmployeeName)
OP提供测试数据和预期结果集后

编辑

试试这个(来自问题的表和测试数据):

DECLARE @Company TABLE (CompanyID int)
DECLARE @TableA TABLE (EmployeeId int,CompanyId int,EmployeeName varchar(30))
DECLARE @TableB TABLE (EmployeeId int,CompanyId int,EmployeeName varchar(30))

set nocount on
INSERT INTO @Company (CompanyID) VALUES (10)
INSERT INTO @Company (CompanyID) VALUES (12)

--INSERT INTO @TableA ( EmployeeId, CompanyId, EmployeeName )--VALUES ( 2, 12, 'someone 2' )
INSERT INTO @TableA ( EmployeeId, CompanyId, EmployeeName )VALUES ( 1, 10, 'someone' )
INSERT INTO @TableA ( EmployeeId, CompanyId, EmployeeName )VALUES ( 3, 12, 'someone 3' )
INSERT INTO @TableA ( EmployeeId, CompanyId, EmployeeName )VALUES ( 3, 12, 'someone 4' )

--INSERT INTO @TableB ( EmployeeId, CompanyId, EmployeeName )--VALUES ( 3, 12, 'someone 3' )
INSERT INTO @TableB ( EmployeeId, CompanyId, EmployeeName )VALUES ( 1, 10, 'someone' )
INSERT INTO @TableB ( EmployeeId, CompanyId, EmployeeName )VALUES ( 2, 12, 'someone 2' )
INSERT INTO @TableB ( EmployeeId, CompanyId, EmployeeName )VALUES ( 3, 12, 'someone 4' )
set nocount off

SELECT coalesce(TableA.CompanyID,TableB.CompanyID) CompanyID,
    TableA.EmployeeName,
    TableB.EmployeeName
FROM @TableA TableA
FULL OUTER jOIN  @TableB TableB ON TableA.CompanyID = TableB.CompanyID AND TableB.EmployeeName = TableA.EmployeeName
WHERE coalesce(TableA.CompanyID,TableB.CompanyID) = 12

输出:

CompanyID   EmployeeName                   EmployeeName
----------- ------------------------------ ------------------------------
12          NULL                           someone 2
12          someone 3                      NULL
12          someone 4                      someone 4

(3 row(s) affected)

答案 1 :(得分:1)

试试这个

DECLARE @Company TABLE 
( 
    CompanyID int 
) 

INSERT INTO @Company (CompanyID) VALUES (10) 
INSERT INTO @Company (CompanyID) VALUES (12) 

DECLARE @TableA TABLE 
( 
    EmployeeId int, 
    CompanyId int, 
    EmployeeName varchar(30) 
) 

DECLARE @TableB TABLE 
( 
    EmployeeId int, 
    CompanyId int, 
    EmployeeName varchar(30) 
) 

INSERT INTO @TableA ( EmployeeId, CompanyId, EmployeeName ) 
VALUES ( 1, 10, 'someone' ) 

--INSERT INTO @TableA ( EmployeeId, CompanyId, EmployeeName ) 
--VALUES ( 2, 12, 'someone 2' ) 

INSERT INTO @TableA ( EmployeeId, CompanyId, EmployeeName ) 
VALUES ( 3, 12, 'someone 3' ) 

INSERT INTO @TableA ( EmployeeId, CompanyId, EmployeeName ) 
VALUES ( 3, 12, 'someone 4' ) 

INSERT INTO @TableB ( EmployeeId, CompanyId, EmployeeName ) 
VALUES ( 1, 10, 'someone' ) 

INSERT INTO @TableB ( EmployeeId, CompanyId, EmployeeName ) 
VALUES ( 2, 12, 'someone 2' ) 

--INSERT INTO @TableB ( EmployeeId, CompanyId, EmployeeName ) 
--VALUES ( 3, 12, 'someone 3' ) 

INSERT INTO @TableB ( EmployeeId, CompanyId, EmployeeName ) 
VALUES ( 3, 12, 'someone 4' ) 

INSERT INTO @TableB ( EmployeeId, CompanyId, EmployeeName )  
VALUES ( 3, 12, 'someone 4' )  

SELECT Company.CompanyID,  
   A.EmployeeNameTableA,  
   A.EmployeeNameTAbleB 
FROM @Company Company  
left OUTER JOIN (select TableA.EmployeeName as EmployeeNameTableA, TableB.EmployeeName as EmployeeNameTableB , 
coalesce(TableA.CompanyID,TableB.CompanyID) as CompanyID 
from @TableA TableA  
FULL OUTER JOIN @TableB TableB ON TableA.CompanyID = TableB.CompanyID and TableB.EmployeeName = TableA.EmployeeName and (tablea.companyid = 12 or tableb.companyid = 12))A ON Company.CompanyID = A.CompanyID  

WHERE Company.CompanyID = 12  

答案 2 :(得分:1)

FULL OUTER JOIN只能在companyID和employeeName上的TableA和TableB之间进行,因为如果它只存在于一个表中,那么这个值就是你想要填充的值。 获得此信息后,您可以与公司进行内部联接以从公司获取其他数据。

FULL OUTER JOIN解决方案:

select Company.companyID, EmployeeNameA, EmployeeNameB
from (
    SELECT isnull(TableA.CompanyID, TableB.CompanyID) as companyID,
        TableA.EmployeeName as EmployeeNameA,
        TableB.EmployeeName as EmployeeNameB
    FROM @TableA TableA 
    FULL OUTER JOIN @TableB TableB ON TableA.EmployeeName = TableB.EmployeeName and TableA.companyID = TableB.companyID
    WHERE
     TableA.CompanyID = 12 or TableB.CompanyID = 12 
) merged
inner join @Company Company
    on merged.companyID = Company.companyID

我个人觉得很难用FULL OUTER JOINS来思考。我对此的处理方法是:通过在受影响的表之间创建UNION,然后使用左连接从两个表中获取数据,从而在需要时获取NULL,在结果中找到所需的独特EmployeeNames。

LEFT JOIN示例:

select c.companyID, a.employeeName, b.employeeName
from  (
    select distinct employeeName, companyID
    from  (
        select a.employeeName, companyID 
        from @tableA  a
        union 
        select b.employeeName, companyID
        from @tableB b
    ) a
) z
inner join @company c
    on c.companyID = z.companyID
left join @tableA  a
    on z.companyID = a.companyID and z.employeeName = a.employeeName
left join @tableB  b
    on z.companyID = b.companyID and z.employeeName = b.employeeName
where z.companyID = 12

答案 3 :(得分:0)

以下是Dimitris Baltas答案的变体,它更接近我的想法。

SELECT Company.CompanyID,
    TableA.EmployeeName as EmployeeNameTableA,
    TableB.EmployeeName as EmployeeNameTableB
FROM @TableA TableA 
FULL OUTER JOIN @TableB TableB ON TableA.EmployeeName = TableB.EmployeeName 
    and TableA.companyID = TableB.companyID
INNER JOIN @Company Company ON (
    Company.CompanyID = TableA.CompanyId OR Company.CompanyID = TableB.CompanyId
)
WHERE Company.CompanyID = 12

我正在寻找的关键事项(这个示例不会这样做,但Dimitris'可能)是对CompanyID进行预过滤,以便执行计划不会筛选每个连接表的所有行在过滤出CompanyID之前。就我而言,两个连接的表格非常慢。

我认为我最终要做的就是继续使用sprocs。