Обновите несколько столбцов, которые начинаются с определенной строки
Я пытаюсь обновить группу столбцов в БД для тестирования функции. У меня есть таблица, созданная с помощью спящего режима, поэтому все столбцы, созданные для встроенного объекта, начинаются с одного и того же имени. Т.е. contact_info_address_street1
, contact_info_address_street2
, так далее.
Я пытаюсь выяснить, есть ли способ сделать что-то для воздействия:
UPDATE table SET contact_info_address_* = null;
Если нет, я знаю, что смогу проделать долгий путь, просто ища способ помочь себе в будущем, если мне нужно будет сделать это снова и снова для другого набора столбцов.
2 ответа
Там нет удобного ярлыка извините. Если вам приходится много заниматься такими вещами, вы можете создать функцию для динамического выполнения sql и достижения своей цели.
CREATE OR REPLACE FUNCTION reset_cols() RETURNS boolean AS $$ BEGIN
EXECUTE (select 'UPDATE table SET '
|| array_to_string(array(
select column_name::text
from information_schema.columns
where table_name = 'table'
and column_name::text like 'contact_info_address_%'
),' = NULL,')
|| ' = NULL');
RETURN true;
END; $$ LANGUAGE plpgsql;
-- run the function
SELECT reset_cols();
Это не очень хорошо, хотя. Лучшей функцией была бы та, которая принимает префикс имени таблицы и столбца как аргументы. Который я оставлю в качестве упражнения для читателей:)
Вам нужен динамический SQL для этого. Поэтому вы должны быть готовы справиться с возможной инъекцией SQL.
Основной запрос
Основной запрос для создания необходимой команды DML может выглядеть следующим образом:
SELECT format('UPDATE tbl SET (%s) = (%s)'
,string_agg (quote_ident(attname), ', ')
,string_agg ('NULL', ', ')
)
FROM pg_attribute
WHERE attrelid = 'tbl'::regclass
AND NOT attisdropped
AND attnum > 0
AND attname ~~ 'foo_%';
Возвращает:
UPDATE tbl SET (foo_a, foo_b, foo_c) = (NULL, NULL, NULL);
Я использую " синтаксис списка столбцов "
UPDATE
сократить код и упростить задачу.Я запрашиваю системные каталоги вместо информационной схемы, потому что последняя, будучи стандартизированной и гарантированно переносимой для основных версий, также печально известна медлительностью и иногда громоздкостью. Есть плюсы и минусы, мы обсуждали это несколько раз здесь, на SO. Поиск по ключевым словам для получения дополнительной информации.
quote_ident()
для имен столбцов предотвращает SQL-внедрение, а также необходимо для любых нестандартных имен столбцов.Вы не упомянули свою версию Postgres. Агрегатная функция
string_agg()
требуется 9.0+.
Полная автоматизация с функцией PL/pgSQL
CREATE OR REPLACE FUNCTION f_update_cols(_tbl regclass, _col_pattern text
, OUT row_ct int, OUT col_ct int)
RETURNS record AS
$func$
DECLARE
_sql text;
BEGIN
SELECT format('UPDATE tbl SET (%s) = (%s)'
,string_agg (quote_ident(attname), ', ')
,string_agg ('NULL', ', ')
)
,count(*)::int
INTO _sql, col_ct
FROM pg_attribute
WHERE attrelid = _tbl
AND NOT attisdropped -- no dropped columns
AND attnum > 0 -- no system columns
AND attname ~~ _col_pattern; -- only columns matching pattern
-- RAISE NOTICE '%', _sql; -- output generated SQL for debugging
EXECUTE _sql;
GET DIAGNOSTICS row_ct = ROW_COUNT;
END
$func$ LANGUAGE plpgsql;
COMMENT ON FUNCTION f_update_cols(regclass, text)
IS 'Updates all columns of table _tbl ($1)
that match _col_pattern ($2) in a LIKE expression.
Returns the count of columns (col_ct) and rows (row_ct) affected.';
Вызов:
SELECT * FROM f_update_cols('myschema.tbl', 'foo%');
Чтобы сделать функцию более практичной, она возвращает информацию, как описано в комментарии. Подробнее о получении статуса результата в plpgsql в руководстве.
Я использую переменную
_sql
держать строку запроса, чтобы я мог собрать количество найденных столбцов (col_ct
) в том же запросе.Тип идентификатора объекта
regclass
это самый эффективный способ автоматически избежать внедрения SQL (и очистить нестандартные имена) для имени таблицы. Вы можете использовать имена таблиц, уточненные схемой, чтобы избежать двусмысленности. Я бы посоветовал сделать это, если у вас есть несколько схем в вашей базе данных! Больше деталей в этом связанном вопросе:
Имя таблицы как параметр функции PostgreSQL