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

时间:2011-04-05 08:03:03

标签: sql postgresql

我的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以在WHEN / ELSE子句中只有一个CASE和10个字段更新?

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

非常感谢, 仙人

3 个答案:

答案 0 :(得分:8)

  

我相信以上是标准的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(因为您确实应该使用IMO :)并想要更“紧凑”的语法,那么请查看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;

答案 1 :(得分:3)

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

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

<小时/> 但就目前而言,对于您的特定查询,您可以使用类似

的内容
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

答案 2 :(得分:0)

如果您需要更多次复制确切的案例(多于2个),您可以使用下一个查询。但是你必须真的需要复制案例,而不是使用test和test2(这不是完全相同的情况)。显然,如果您需要将测试/测试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