【问题标题】:SQL CASE statement, one result seems unreachableSQL CASE 语句,一个结果似乎无法到达
【发布时间】:2015-02-06 14:39:59
【问题描述】:

我正在尝试解决我现在维护的大量数据库存储过程,但我遇到了一个令人困惑的问题。我不知道它是否包含冗余/无用代码,或者我是否缺少一些细微差别,因为我仍然只是 SQL 语言的中级。这是有问题的代码部分:

UPDATE #NewValues
SET ValidNumber = CASE WHEN SP.ModelNumber IS NULL THEN 0
                            ELSE 1
                        END
FROM #NewValues NV
LEFT OUTER JOIN Stage.Products SP
    ON NV.SKU = SP.SKU
    AND (NV.ModelNumber = SP.ModelNumber OR NV.UPC = SP.ModelNumber)
WHERE NV.SKU IN (
    SELECT NV.SKU
    FROM #NewValues NV
    INNER JOIN Stage.Products SP
        ON NV.SKU = SP.SKU
        AND (NV.ModelNumber = SP.ModelNumber OR NV.UPC = SP.ModelNumber)
    WHERE NV.ValidNumber = 1
)

在我看来,SP.ModelNumber 不会为 NULL,因为嵌套的 SELECT 语句永远不会返回带有 SP.ModelNumber NULL 结果的 SKU。所以唯一能做的就是SET ValidNumber = 1。那是对的吗?同样,我不确定这里是否还有其他事情我无法将其纳入逻辑,但似乎嵌套的 SELECT 语句将是您实现相同目标所需的全部内容结果。由于此代码位于更大的查询中的方式,我很难尝试建立一个与正常使用相匹配的情况来测试它,特别是因为我不确定ValidNumber 值是什么将是这部分代码运行之前。

【问题讨论】:

  • 这就是我们所说的“白痴证明”。您可能会惊讶于人们会以最意想不到的方式输入数据。作为后端开发人员,我们必须考虑人们输入数据的所有可能的愚蠢方式(无意冒犯)。开个小玩笑:您是否见过吹风机上的警告标签:不要在淋浴时使用它?
  • 仅仅因为至少一个 sku 有一个有效的 modelNumber 并不意味着所有这些 sku 都有有效的 modelNumbers

标签: sql sql-server tsql sql-server-2005 case


【解决方案1】:

这取决于数据的性质。如果单个Sku 可以在newvalues 表中有多个记录,则可能需要outer join,并且可以设置validnumber = 0


这里有一些示例数据试图说明(下面的小提琴):

create table newvalues (validnumber int, sku int, modelnumber int, upc int);
create table products (sku int, modelnumber int);

insert into newvalues values (1, 1, 1, 1), (0, 1, 1, 1), (null, 1, 2, 2);
insert into products values (1, 1);

如您所见,sku = 1 的 newvalues 表中有多个结果。


然后是update 声明:

UPDATE NewValues
SET validnumber = CASE WHEN SP.ModelNumber IS NULL THEN 0
                            ELSE 1
                        END
FROM NewValues NV
LEFT OUTER JOIN Products SP
    ON NV.SKU = SP.SKU
    AND (NV.ModelNumber = SP.ModelNumber OR NV.UPC = SP.ModelNumber)
WHERE NV.SKU IN (
    SELECT NV.SKU
    FROM NewValues NV
    INNER JOIN Products SP
        ON NV.SKU = SP.SKU
        AND (NV.ModelNumber = SP.ModelNumber OR NV.UPC = SP.ModelNumber)
    WHERE NV.ValidNumber = 1
);

这会更新所有行,一些为 0,一些为 1,因为其中至少有一个存在于带有 inner join 的子查询中。这不会否定outer join,因为同一个sku 存在多行,因此它们都会得到更新(即使是sp.modelnumber is null 的那些)

【讨论】:

  • 感谢您的解释。我想我错过了如何构建表中已有数据的一个方面。注意:我必须使用insert into newvalues select (1, 1, 1, 1) union all select (0, 1, 1, 1) union all select (null, 1, 2, 2) 来插入多行。我想这是对 SQL Server 更高版本的更改?我用的是 2005。
【解决方案2】:

原始编码器只是安全的。 #NewValues 中可能有一个项目在 Stage.Products 中不存在,如果是这种情况,LEFT JOIN 将导致 SP 中的所有字段在不匹配的情况下为 NULL。

【讨论】:

  • 是的,但是您删除了where 子句中的NULL 值?
  • 这是一个更新,如果它是有效的,而不再有效,因为它被删除了怎么办?
  • 除了那些也被 where 子句消除,因为 where 子句查询使用相同条件的内连接,这将确保左连接将产生空 SP.ModelNumber 的任何 SKU被内部连接的 where in 消除。
【解决方案3】:

我可能记错了,但是你用第一个WHERE做什么?

WHERE NV.SKU IN (
    SELECT NV.SKU
    FROM #NewValues NV
    INNER JOIN Stage.Products SP
        ON NV.SKU = SP.SKU
        AND (NV.ModelNumber = SP.ModelNumber OR NV.UPC = SP.ModelNumber)
    WHERE NV.ValidNumber = 1
)

你在上面的JOIN做同样的事情。

我会去:

UPDATE #NewValues
SET ValidNumber = CASE WHEN SP.ModelNumber IS NULL THEN 0
                        ELSE 1
                    END
FROM #NewValues NV
INNER JOIN Stage.Products SP
    ON NV.SKU = SP.SKU
    AND (NV.ModelNumber = SP.ModelNumber OR NV.UPC = SP.ModelNumber)
WHERE NV.ValidNumber = 1

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-02-17
    • 1970-01-01
    • 2021-12-27
    • 1970-01-01
    相关资源
    最近更新 更多