Как выполнить динамический оператор c SQL в одном операторе Select? - PullRequest
0 голосов
/ 09 апреля 2020

Мне просто интересно, как оценить содержимое динамического c SQL, используя один выбор; это пример. Это только пример. но я хотел бы динамически функционировать и управлять с помощью одного выбора. (Я знаю, что sqls предназначены только для SELECT, а не для изменения ... но в этой глубокой задаче я становлюсь сумасшедшим разработчиком)

SELECT 'SELECT SETVAL(' || chr(39) || c.relname || chr(39)|| ' , 
(SELECT MAX(Id)+1 FROM '  || regexp_replace(c.relname, '_[a-zA-Z]+_[a-zA-Z]+(_[a-zA-Z0-9]+)?', '', 'g')   ||' ), true );' 
FROM pg_class c WHERE c.relkind = 'S';

Исходный вывод:

SELECT SETVAL('viewitem_id_seq' , (SELECT MAX(Id)+1 FROM viewitem ), true );
SELECT SETVAL('userform_id_seq' , (SELECT MAX(Id)+1 FROM userform ), true );

Это динамическое предложение c: (ВЫБЕРИТЕ МАКС. (Id) +1 FROM '|| regexp_replace (c .relname,' [a-zA-Z] + [a-zA-Z] ] + (_ [a-zA-Z0-9] +)? ',' ',' g ')

- это строка, которая генерирует в качестве вывода a SQL, как вычислить в той же строке это утверждение?

Желаемый вывод:

SELECT SETVAL('viewitem_id_seq' , 25, true );
SELECT SETVAL('userform_id_seq' , 85, true );

спасибо!

1 Ответ

1 голос
/ 09 апреля 2020

Если это столбцы 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() работает

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...