SQL - 使用 CASE 语句更新,我需要多次重复相同的 CASE 吗?

发布于 2024-10-29 22:57:43 字数 745 浏览 1 评论 0原文

我的 UPDATE 语句大致如下:

UPDATE  customer
SET  forenames=ot.forenames,
     surname =

CASE WHEN ot.safeplace IS NULL
THEN 'test SAFEPLACE IS NULL'
ELSE 'test Safeplace IS NOT NULL'
END,

     middlename =

CASE WHEN ot.safeplace IS NULL
THEN 'test2 SAFEPLACE IS NULL'
ELSE 'test2 Safeplace IS NOT NULL'
END,

FROM    order_transaction ot

WHERE   customer.custid = ot.custid
AND ot.trans_orderid = 5678
AND customer.custid = 1234

以上有效。它基本上检查另一个表中的字段是否为 NULL,然后相应地更新客户的“姓氏”和“中间名”。正如您在上面看到的,我重复了相同的 CASE 语句两次。我的问题是 - 有没有办法可以只指定一次 CASE 语句?

问题是,如果我说要根据某个条件更新10个字段,是否需要包含10个类似的CASE条件?或者是否可以将 SQL 改进为只有 1 个 CASE,并在 WHEN / ELSE 子句中更新 10 个字段?

(我使用的是 Postgresql 8.2 数据库,但我相信上面是标准 SQL)。

非常感谢, 仙人

My UPDATE statement goes along the lines of:

UPDATE  customer
SET  forenames=ot.forenames,
     surname =

CASE WHEN ot.safeplace IS NULL
THEN 'test SAFEPLACE IS NULL'
ELSE 'test Safeplace IS NOT NULL'
END,

     middlename =

CASE WHEN ot.safeplace IS NULL
THEN 'test2 SAFEPLACE IS NULL'
ELSE 'test2 Safeplace IS NOT NULL'
END,

FROM    order_transaction ot

WHERE   customer.custid = ot.custid
AND ot.trans_orderid = 5678
AND customer.custid = 1234

The above works. It basically checks if a field in another table is NULL or not, and then updates the customer's "surname" and "middlename" accordingly. As you can see above, I have repeated the same CASE statement twice. My question is - is there a way I can specify the CASE statement just once?

The point is, if I say wanted to update 10 fields based on a certain condition, do I need to include 10 similar CASE conditions? Or can the SQL be improved to have just one CASE, and 10 field updates within the WHEN / ELSE clauses?

(I'm using a Postgresql 8.2 database but I believe the above is standard SQL).

Many thanks,
Rishi

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

呆萌少年 2024-11-05 22:57:44

我相信上面是标准的SQL

实际上,它不是。标准 SQL 没有 UPDATE..FROM 语法。相反,您需要为每个 SET 子句使用一个标量子查询,并为 EXISTS 使用另一个标量子查询,因此标准语法更加重复,例如

UPDATE customer
   SET forenames = (
                    SELECT ot.forenames
                      FROM order_transaction AS ot
                     WHERE customer.custid = ot.custid
                           AND ot.trans_orderid = 5678
                   ),
       surname = (
                  SELECT CASE 
                            WHEN ot.safeplace IS NULL 
                               THEN 'test SAFEPLACE IS NULL'
                            ELSE 'test Safeplace IS NOT NULL'
                         END
                    FROM order_transaction AS ot
                   WHERE customer.custid = ot.custid
                         AND ot.trans_orderid = 5678
                 ),
       middlename = (
                     SELECT CASE 
                               WHEN ot.safeplace IS NULL 
                                  THEN 'test SAFEPLACE IS NULL'
                               ELSE 'test Safeplace IS NOT NULL'
                            END
                       FROM order_transaction AS ot
                      WHERE customer.custid = ot.custid
                            AND ot.trans_orderid = 5678
                    )
 WHERE customer.custid = 1234
       AND EXISTS (
                   SELECT * 
                     FROM order_transaction AS ot
                    WHERE customer.custid = ot.custid
                          AND ot.trans_orderid = 5678
                  );

虽然语法看起来重复,但一个好的优化器应该能够识别重复并相应地进行优化。当然,当前版本的 SQL 产品是否确实在实践中很好地优化了这一点则是另一回事。但请考虑一下:如果您选择的 SQL 产品支持标准语法,但实际上没有正确优化它,那么“支持”还有什么价值吗?

如果您希望使用标准 SQL(在我看来,您确实应该这样做:) 并且想要更“紧凑”的语法,那么请查看 MERGEMERGE (SQL) 例如可能看起来更像这样:

MERGE INTO customer
   USING (
          SELECT ot.custid, ot.forenames, 
                 CASE 
                     WHEN ot.safeplace IS NULL 
                        THEN 'test SAFEPLACE IS NULL'
                     ELSE 'test Safeplace IS NOT NULL'
                  END
             FROM order_transaction AS ot
            WHERE ot.trans_orderid = 5678   
         ) AS source (custid, forenames, safeplace_narrative)
   ON customer.custid = source.custid
      AND customer.custid = 1234
WHEN MATCHED THEN
   UPDATE 
      SET forenames = source.forenames, 
          surname = source.safeplace_narrative, 
          middlename = source.safeplace_narrative;

I believe the above is standard SQL

Actually, it isn't. Standard SQL does not have a UPDATE..FROM syntax. Rather, you need to use a scalar subquery for each SET clause plus another for EXISTS, so the Standard syntax is even more repetitive e.g.

UPDATE customer
   SET forenames = (
                    SELECT ot.forenames
                      FROM order_transaction AS ot
                     WHERE customer.custid = ot.custid
                           AND ot.trans_orderid = 5678
                   ),
       surname = (
                  SELECT CASE 
                            WHEN ot.safeplace IS NULL 
                               THEN 'test SAFEPLACE IS NULL'
                            ELSE 'test Safeplace IS NOT NULL'
                         END
                    FROM order_transaction AS ot
                   WHERE customer.custid = ot.custid
                         AND ot.trans_orderid = 5678
                 ),
       middlename = (
                     SELECT CASE 
                               WHEN ot.safeplace IS NULL 
                                  THEN 'test SAFEPLACE IS NULL'
                               ELSE 'test Safeplace IS NOT NULL'
                            END
                       FROM order_transaction AS ot
                      WHERE customer.custid = ot.custid
                            AND ot.trans_orderid = 5678
                    )
 WHERE customer.custid = 1234
       AND EXISTS (
                   SELECT * 
                     FROM order_transaction AS ot
                    WHERE customer.custid = ot.custid
                          AND ot.trans_orderid = 5678
                  );

While the syntax looks repetitive, a good optimizer should be able to recognize the repetition and optimize accordingly. Whether the current version of your SQL product actually does a good job of optimizing this in practise is of course another matter. But consider this: if your SQL product of choice supports the Standard syntax but doesn't actually optimize it properly is the "support" worth anything?

If you are looking to use Standard SQL (as you indeed should IMO :) and want a more "compact" syntax then take a look at MERGE or MERGE (SQL) e.g. could look more like this:

MERGE INTO customer
   USING (
          SELECT ot.custid, ot.forenames, 
                 CASE 
                     WHEN ot.safeplace IS NULL 
                        THEN 'test SAFEPLACE IS NULL'
                     ELSE 'test Safeplace IS NOT NULL'
                  END
             FROM order_transaction AS ot
            WHERE ot.trans_orderid = 5678   
         ) AS source (custid, forenames, safeplace_narrative)
   ON customer.custid = source.custid
      AND customer.custid = 1234
WHEN MATCHED THEN
   UPDATE 
      SET forenames = source.forenames, 
          surname = source.safeplace_narrative, 
          middlename = source.safeplace_narrative;
澜川若宁 2024-11-05 22:57:44

如果要在同一查询级别上执行 CASE,则需要重复 CASE,就像在 group by 子句中重复计算列一样。

您的示例查询根本没有透露您想要做什么,您是否真的将所有记录更新为相同的值(固定文本),以及每条记录的所有列。如果您更新以使问题更相关,可能会有更好的答案。


But for now, for your specific query, you can use something like this

UPDATE  customer
SET  forenames=ot.forenames,
     surname = fixedText,
     middlename = fixedText    
FROM (select o.*, CASE
      WHEN safeplace IS NULL
      THEN 'test2 SAFEPLACE IS NULL'
      ELSE 'test2 Safeplace IS NOT NULL'
      END fixedText
      from order_transaction o) ot
WHERE   customer.custid = ot.custid
AND ot.trans_orderid = 5678
AND customer.custid = 1234

If you wanted to perform the CASE on the same query level, you would need to repeat the CASE, just as you would repeat a computed column in a group by clause.

Your sample query does not reveal at all what you want to do, are you really updating all records to the same value (fixed text), as well as all columns per record. If you updated to make the question more relevant, there is probably a better answer.


But for now, for your specific query, you can use something like this

UPDATE  customer
SET  forenames=ot.forenames,
     surname = fixedText,
     middlename = fixedText    
FROM (select o.*, CASE
      WHEN safeplace IS NULL
      THEN 'test2 SAFEPLACE IS NULL'
      ELSE 'test2 Safeplace IS NOT NULL'
      END fixedText
      from order_transaction o) ot
WHERE   customer.custid = ot.custid
AND ot.trans_orderid = 5678
AND customer.custid = 1234
醉生梦死 2024-11-05 22:57:44

如果您需要多次复制确切的情况(远多于 2 次),您可以使用下一个查询。但你必须真正需要复制案例,而不是 test 和 test2 (这不是完全相同的案例)。显然,如果您需要将 test / test 2 或其他文本连接到结果,那么您可以在 select 语句中执行此操作。例如: surname = 'test '+st.result 因此有可能进行一些“黑客攻击”。

UPDATE  customer
SET  forenames=ot.forenames,
     surname = st.result,
     middlename = st.result

FROM    order_transaction ot
JOIN (select 1 as ID,'test SAFEPLACE IS NULL' as result 
      union
      select 2,'test SAFEPLACE IS NULL') st on case when ot.safeplace is null then 1 else 2 end = st.id

WHERE   customer.custid = ot.custid
AND ot.trans_orderid = 5678
AND customer.custid = 1234

If you need to copy the exact case more times (alot more then 2) you can use the next query. But you have to really need to copy the case, not with test and test2 (that is not exactly the same case). Evidently if you need to concatenate text like test / test 2 or whatever to a result then you can do it in the select statement. ex: surname = 'test '+st.result so there are some possibilities to do some 'hacks'.

UPDATE  customer
SET  forenames=ot.forenames,
     surname = st.result,
     middlename = st.result

FROM    order_transaction ot
JOIN (select 1 as ID,'test SAFEPLACE IS NULL' as result 
      union
      select 2,'test SAFEPLACE IS NULL') st on case when ot.safeplace is null then 1 else 2 end = st.id

WHERE   customer.custid = ot.custid
AND ot.trans_orderid = 5678
AND customer.custid = 1234
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文