Если это столбцы serial
или identity
, то лучше использовать pg_get_serial_sequence()
, чтобы получить связь между столбцом таблицы и ее последовательностью.
На самом деле вы можете запустить Dynami c SQL внутри оператора SQL, используя query_to_xml()
. Я использую следующий скрипт, если мне нужно синхронизировать последовательности для serial
(или identity
) столбцы с их действительными значениями:
with sequences as (
-- this query is only to identify all sequences that belong to a column
-- it's essentially similar to your select * from pg_class where reltype = 'S'
-- but returns the sequence name, table and column name to which the
-- sequence belongs
select *
from (
select table_schema,
table_name,
column_name,
pg_get_serial_sequence(format('%I.%I', table_schema, table_name), column_name) as col_sequence
from information_schema.columns
where table_schema not in ('pg_catalog', 'information_schema')
) t
where col_sequence is not null
), maxvals as (
select table_schema, table_name, column_name, col_sequence,
--
-- this is the "magic" that runs the SELECT MAX() query
--
(xpath('/row/max/text()',
query_to_xml(format('select max(%I) from %I.%I', column_name, table_schema, table_name), true, true, ''))
)[1]::text::bigint as max_val
from sequences
)
select table_schema,
table_name,
column_name,
col_sequence,
coalesce(max_val, 0) as max_val,
setval(col_sequence, coalesce(max_val, 1)) --<< this uses the value from the dynamic query
from maxvals;
Часть Dynami c здесь - это вызов query_to_xml()
Сначала я использую format()
, чтобы правильно разобраться с идентификаторами. Это также облегчает написание SQL, так как не требует объединения. Таким образом, для каждой таблицы, возвращаемой первым CTE, выполняется что-то вроде этого:
query_to_xml('select max(id) from public.some_table', true, true, '')
Это возвращает что-то вроде:
<row xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<max>42</max>
</row>
Значение извлекается из значения XML используя xpath () и преобразуя его в число, которое затем используется в последнем SELECT для фактического вызова setval()
Вложение с несколькими CTE используется только для того, чтобы сделать каждую часть более читабельной.
Тот же подход, например, используется для поиска количества строк для всех таблиц
Некоторые фон о том, как query_to_xml()
работает