Сегодня опишу вам как решить следующую сверхспецифическую задачу: у нас в БД PostgreSQL есть таблица некоторой структуры:
Вследствие каких-то причин в проекте решено соединить данные полей
Таким образом, новая таблица и запись в ней выглядит так:
Естественно, будем все максимально автоматизировать. Для работы нам пригодятся некоторые функции для работы с hstore и немного php, просто чтобы сформировать общий текст запроса. Общий текст запроса выглядит вот так:
Итак, что же здесь происходит? Начнем с внутренней части.
1. Для значения каждого из полей
2. Далее нам требуется избавиться от
3. Потом из объединенной строки мы создаем массив, разбивая строку по разделителю
4. И, наконец, полученный массив передаем в метод
Отдельно замечу, что разделителем выбран
С использованием php можно создать такой скрипт генерации и выполнения запроса:
По ссылке - улучшенный гист с кодом, обрабатывающим даже поле типа
id | name | attr_1 | attr_2 | attr_3 |
---------------------------------------|
1 | NAME | v1 | v2 | v3 |
Вследствие каких-то причин в проекте решено соединить данные полей
attr_1, attr_2, attr_3
в одно поле attrs
типа hstore.Таким образом, новая таблица и запись в ней выглядит так:
id | name | attrs |
---------------------------------------------------------|
1 | NAME | attr_1 => v1, attr_2 => v2, attr_3 => v3 |
Естественно, будем все максимально автоматизировать. Для работы нам пригодятся некоторые функции для работы с hstore и немного php, просто чтобы сформировать общий текст запроса. Общий текст запроса выглядит вот так:
UPDATE tableName
SET attrs =
hstore(
string_to_array(
rtrim(
(CASE WHEN (attr_1 IS NOT NULL) THEN ('attr_1' || '~~~' || attr_1 || '~~~') ELSE '' END)
||
(CASE WHEN (attr_2 IS NOT NULL) THEN ('attr_2' || '~~~' || attr_2 || '~~~') ELSE '' END)
||
(CASE WHEN (attr_3 IS NOT NULL) THEN ('attr_3' || '~~~' || attr_3 || '~~~') ELSE '' END),
'~'
),
'~~~'
)
)
Итак, что же здесь происходит? Начнем с внутренней части.
1. Для значения каждого из полей
attr_1, attr_2, attr_3
мы создаем строку вида НазваниеПоля~~~ЗначениеПоля~~~
или просто пустую строку, если значение поля NULL
. Все эти строки объединяем в одну результрующую.2. Далее нам требуется избавиться от
~
в конце объединенной строки. В этом нам помогает rtrim
.3. Потом из объединенной строки мы создаем массив, разбивая строку по разделителю
~~~
.4. И, наконец, полученный массив передаем в метод
hstore
. Готово.Отдельно замечу, что разделителем выбран
~~~
потому, что встретить его в значениях полей attr_1, attr_2, attr_3
невозможно. Если в ваших данных может встречаться такой набор символов - используйте другой разделитель из более "странных" символов.С использованием php можно создать такой скрипт генерации и выполнения запроса:
$fields = [
'attr_1',
'attr_2',
'attr_3',
// еще поля
];
$glue = '~~~';
$selectPattern = "(CASE WHEN (%s IS NOT NULL) THEN ('%s' || '$glue' || %s || '$glue') ELSE '' END)";
$select = [];
foreach ($fields as $field) {
$select[] = vsprintf($selectPattern, array_fill(0, 3, $field);
}
$select = implode(' || ', $select);
$this->runSql("
UPDATE {$table}
SET attrs = hstore(string_to_array(rtrim(({$select}), '~'), '{$glue}'))
");
По ссылке - улучшенный гист с кодом, обрабатывающим даже поле типа
datetime
.