SQL - обновить с помощью оператора CASE, нужно ли повторять один и тот же CASE несколько раз? - PullRequest
10 голосов
/ 05 апреля 2011

Мой оператор 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, чтобы иметь только один CASE и 10 обновлений полей в предложениях WHEN / ELSE?

(я использую базу данных Postgresql 8.2, но я верю, что это стандартный SQL).

Большое спасибо, Риши

Ответы [ 3 ]

8 голосов
/ 05 апреля 2011

Я полагаю, что это стандартный 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 :), и хотите более «компактный» синтаксис, взгляните на MERGE или MERGE (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;
3 голосов
/ 05 апреля 2011

Если вы хотите выполнить 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
0 голосов
/ 05 апреля 2011

Если вам нужно скопировать точный регистр больше раз (много больше 2), вы можете использовать следующий запрос.Но вам действительно нужно скопировать кейс, а не с test и test2 (это не совсем тот же кейс).Очевидно, что если вам нужно объединить текст, такой как test / test 2 или что-то еще, к результату, вы можете сделать это в операторе selectex: surname = 'test' + st.result, поэтому есть некоторые возможности сделать несколько '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
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...