如果行不存在,如何输出行

时间:2019-02-12 07:36:02

标签: sql-server

由TableItem列链接的两个表。 第一个表(名称项)具有ItemNumbers,第二个表具有颜色(Tablename Color)。每个项目的可用颜色是红色,蓝色,绿色和黑色。

每个项目在色表上必须具有全部4种颜色。 如果不是,则查询应输出Itemnumber和缺少的颜色。 对于每种错过的颜色,一条输出线。

不知道是否有可能输出这种混乱的情况。

希望有人能给我提示。

2 个答案:

答案 0 :(得分:2)

要显示一行,行必须存在于某个地方 ,该行可以是物理表中的,也可以是在脚本运行中创建的。您可以使用表变量(DECLARE @Color TABLE (Color VARCHAR(20))和少量插入)或使用VALUES表来随时创建这些颜色:

SELECT
    C.Color
FROM
    (VALUES
        ('Red'),
        ('Green'),
        ('Blue'),
        ('Black')
    ) AS C (Color)

现在我们用CROSS JOIN Items所有这些颜色,这种连接将导致每个项目需要存在的所有颜色。

;WITH ForcedColors AS
(
    SELECT
        C.Color
    FROM
        (VALUES
            ('Red'),
            ('Green'),
            ('Blue'),
            ('Black')
        ) AS C (Color)
)
SELECT
    I.ItemNumber,
    FC.Color
FROM
    Items AS I
    CROSS JOIN ForcedColors AS FC

现在使用此设置,我们对每个项目的实际可用颜色使用LEFT JOIN,因此如果表Color上存在颜色,则行将匹配,如果不存在则返回NULL

;WITH ForcedColors AS
(
    SELECT
        C.Color
    FROM
        (VALUES
            ('Red'),
            ('Green'),
            ('Blue'),
            ('Black')
        ) AS C (Color)
)
SELECT
    I.ItemNumber,
    ForcedColor = FC.Color,
    AvailableColor = C.Color
FROM
    Items AS I
    CROSS JOIN ForcedColors AS FC
    LEFT JOIN Color AS C ON
        I.ItemNumber = C.ItemNumber AND
        FC.Color = C.Color

现在要显示缺少的颜色,只需显示NULL表中具有Color的颜色即可。

;WITH ForcedColors AS
(
    SELECT
        C.Color
    FROM
        (VALUES
            ('Red'),
            ('Green'),
            ('Blue'),
            ('Black')
        ) AS C (Color)
)
SELECT
    I.ItemNumber,
    ForcedColor = FC.Color,
    AvailableColor = C.Color
FROM
    Items AS I
    CROSS JOIN ForcedColors AS FC
    LEFT JOIN Color AS C ON
        I.ItemNumber = C.ItemNumber AND
        FC.Color = C.Color
WHERE
    C.Color IS NULL

或者另一种方法是使用NOT EXISTS而不是WHERE C.Color IS NULL

;WITH ForcedColors AS
(
    SELECT
        C.Color
    FROM
        (VALUES
            ('Red'),
            ('Green'),
            ('Blue'),
            ('Black')
        ) AS C (Color)
)
SELECT
    I.ItemNumber,
    ForcedColor = FC.Color
FROM
    Items AS I
    CROSS JOIN ForcedColors AS FC
WHERE
    NOT EXISTS (SELECT 'color not available' FROM Color AS C 
                WHERE I.ItemNumber = C.ItemNumber AND FC.Color = C.Color)

答案 1 :(得分:0)

您正在描述多对多关系,这意味着items表中的每一行都可以与colors表中的多行链接,而{{1}中的每一行}表可以与colors表中的多行链接。

在关系数据库中创建这种关系的正确方法是使用三个表:一个表用于items,一个表用于items,一个表用于colors(已知作为桥接表)-它将具有两列-项目ID和颜色ID,它们都使用一对多外键约束来引用其他表,并且两者的组合是桥接表的主键:

itemToColor

使用此结构,您的问题的答案变得微不足道-您想测试Item ----- Id, (PK) Name (any other item related columns here) Color ---- Id, (PK) Name (any other color related columns here) ItemToColor ---- ItemId (FK To Items) ColorId (FK To Colors) PRIMARY KEY (ItemId, ColorId) 表的记录计数是否等于其他表的记录计数的乘积:

ItemToColor