Использовать CASE для выбора столбцов в запросе UPDATE?

13

Я могу использовать, CASEчтобы выбрать столбцы для отображения в SELECTзапросе (Postgres), например так:

SELECT CASE WHEN val = 0 THEN column_x
            WHEN val = 1 THEN column_y
            ELSE 0
       END AS update, ...

Возможно ли вообще что-то подобное при выполнении UPDATEзапроса в Postgres (то есть выбрать, какие столбцы следует обновить)? Я предполагаю, что нет, так как я ничего не мог найти по этому поводу, но, возможно, у кого-то есть разумная альтернатива (помимо использования процедуры или обновления каждого столбца с помощью, CASEчтобы определить, следует ли присвоить значению столбца новое значение или просто переназначить существующее значение). Если нет легкой альтернативы, я, конечно, тоже приму это как ответ.

Дополнительная информация : в моем случае у меня есть 14 потенциальных столбцов, которые могут быть обновлены, при этом обновляется только один столбец для соответствующей строки (обновляемая таблица объединяется с другим в запросе). Количество строк для обновления, скорее всего, будет варьироваться, может быть десятки или сотни. Я считаю, что для условий присоединения имеются индексы.

newenglander
источник

Ответы:

26

Если вы указываете, что столбец должен быть обновлен, он всегда будет обновляться, но вы можете изменить значение, которое вы указали условно, и вернуть исходные значения в зависимости от ваших условий. Что-то типа:

UPDATE some_table
SET    column_x = CASE WHEN should_update_x THEN new_value_for_x ELSE column_x END
     , column_y = CASE WHEN should_update_y THEN new_value_for_y ELSE column_y END
     , column_z = CASE WHEN should_update_z THEN new_value_for_z ELSE column_z END
FROM   ...

Таким образом, если условия для обновления определенного столбца не подходят, вы просто возвращаете его текущее значение.

Обратите внимание , что каждая строка соответствует будет видеть обновление (даже если все столбцы в конечном итоге получить набор для значений , которые они уже есть) , если только вы явно ворота это обстоятельство вы фильтрации и где положения, которые могут быть проблемы с производительностью (там будет если запись, индексы будут обновлены, соответствующие триггеры сработают, ...) если не смягчены.

Дэвид Спиллетт
источник
Спасибо за подсказку о том, что все обновляется, если это происходит медленно, я могу воспользоваться предложением @Colin 't Hart иметь несколько операторов обновления.
newenglander
Вы можете полностью решить эту проблему, убедившись, что предложения ON и WHERE отфильтровывают все строки, в которых не требуется никаких изменений, но это может означать повторение всех ваших условий как в предложении SET, так и в предложении WHERE (если только нет более простой общей проверки, что на 100% эквивалентно всем этим условиям). На этом этапе этот метод может быть еще более эффективным, но метод множественных обновлений может быть проще в обслуживании.
Дэвид Спиллетт
Также имейте в виду, что обновление столбца до того же значения приведет к созданию повторного файла
Colin 't Hart
@Colin: Да, любое обновление будет проходить через журнал транзакций БД, включая обновления, которые по сути являются NoOps из-за того, что поля имеют те же значения, что и раньше. Помимо потенциальной возможности немедленной проблемы с производительностью, это может быть важным фактором, если использовать репликацию, разностное резервное копирование, доставку журналов и т. Д., Поскольку дополнительные операции обновления строки увеличат пространство / полосу пропускания, необходимые для них.
Дэвид Спиллетт
Спасибо вам обоим за советы, в моем случае одно заявление об обновлении работало нормально.
newenglander
5

Сколько разных комбинаций столбцов для обновления у вас есть? Сколько строк всей таблицы будет обновлено? Имеются ли индексы для быстрого доступа к строкам для обновления?

В зависимости от ответов на эти вопросы вы можете выполнить несколько операторов обновления, по одному для каждого столбца, который вы хотите обновить, и поместить условие в значение этого столбца в предложении where обновления, чтобы нулевые строки обновлялись, если этот столбец имеет неправильное значение.

Попробуйте думать на основе множеств, не думайте, что для обновления нужно обновить одну строку, найденную по первичному ключу.

Колин т Харт
источник
Спасибо за ответ. Я добавил еще немного информации в свой вопрос, надеюсь, это понятно. Это хорошая альтернатива с несколькими операторами обновления (я бы предпочел один оператор обновления, но я вижу, что здесь есть преимущество).
newenglander
Это может быть ответ, который я ищу, но вы хотите поставить update column_x = new_value_for_x, где @val = 0. Я могу поэкспериментировать с чем-то подобным. Выглядит смешно Это не легче сделать, если val = 0 начать обновление column_x = new_value_for_x и т. Д.
CashCow
-1
update Practicing  -- table you will be updating
 set email = case -- column you will be updating
    when FName = 'Glenn' then 'Ace@Assasin.com'
       when FName = 'Riddick' then 'fallguy@Drunk.com'
       when FName = 'Jeffrey' then 'sorcerer@wizcom'
       else email
    end
user134695
источник
Это обновление только одного столбца, в то время как спрашивающий хочет знать, как обновить различные столбцы в зависимости от условий.
Colin 't Hart