如何联接这些表以获取所有表的完整结果集?

时间:2019-05-01 14:39:27

标签: sql sql-server sql-server-2017

我有一个实体表A

我有商品表B

我有实体项目的表C及其关联的配置值。

我正在寻找一个视图,该视图将为我返回实体+项的每种组合的一行,并使用表C中的数据(如果存在)。

此外,如果TableB中不存在TableC中的项目,我也希望这些项目

例如,

Table A 
Entity 1
Entity 2

Table B
Item X
Item Y
Item Z

Table C
Entity 1    Item X    True
Entity 1    Item Y    False
Entity 2    Item X    False
Entity 2    Item J    False


Result Table Wanted
Entity 1    Item X    True
Entity 1    Item Y    False
Entity 1    Item Z    Null
Entity 2    Item X    False
Entity 2    Item Y    Null
Entity 2    Item Z    Null
Entity 2    Item J    False

出于某种原因,我为此空白。自从我使用SQL以来已经有一段时间了,所以也许我缺少明显的东西。有人可以帮助我确定编写此查询所需的语法吗?

我已经接近使用CROSS JOIN

SELECT *
FROM Entities
CROSS JOIN Items
LEFT OUTER JOIN EntityItems 
    ON Entities.ID = EntityItems.EntityID
    AND Items.ID = EntityItems.ItemID

这将返回除项目C中表C中的行以外的所有内容。

更新:从头开始,它实际上返回了我太多行。那就是我现在正在玩的。

我正在使用MS Sql Server 2017

1 个答案:

答案 0 :(得分:2)

您的cross join / left join是正确的方法:

SELECT e.EntityID, i.ItemId, COALESCE(ei.value, 'false') as value
FROM Entities e CROSS JOIN
     Items i LEFT JOIN
     EntityItems ei
    ON e.ID = ei.EntityID AND
       i.ID = ei.ItemID;

但是,这假定ItemId已使用外键关系正确定义。您似乎有无效的ItemId。您可以解决此问题:

SELECT e.EntityID, i.ItemId, COALESCE(ei.value, 'false') as value
FROM Entities e CROSS JOIN
     (SELECT i.ItemId
      FROM Items i
      UNION  -- on purpose to remove duplicates
      SELECT ei.ItemId
      FROM EntityItems ei
     ) i LEFT JOIN
     EntityItems ei
    ON e.ID = ei.EntityID AND
       i.ID = ei.ItemID;

但是,我强烈建议您修复数据(即,将J添加到项目表)并添加:

alter table entityitems add constraint fk_entityitems_entityid
    foreign key (entityid) references entities(entityid);

alter table entityitems add constraint fk_entityitems_itemid
    foreign key (itemid) references entities(itemid);

这将帮助您在修复数据后确保数据完整性(向前移动)。

编辑:

啊,您不希望所有实体上都有其他项目ID。如果是这样:

SELECT e.EntityID, i.ItemId, COALESCE(ei.value, 'false') as value
FROM Entities e CROSS JOIN
     Items i LEFT JOIN
     EntityItems ei
    ON e.ID = ei.EntityID AND
       i.ID = ei.ItemID;
UNION ALL
SELECT ei.EntityId, ei.ItemId, ei.value
FROM EntityItems ei
WHERE NOT EXISTS (SELECT 1 FROM Items i WHERE i.ItemId = ei.ItemId);