【问题标题】:How to execute a dynamic SQL statement in a single Select statement?如何在单个 Select 语句中执行动态 SQL 语句?
【发布时间】:2020-04-09 21:08:24
【问题描述】:

我只是想知道如何使用一个选择来评估动态 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 );

这是动态句: (SELECT MAX(Id)+1 FROM ' || regexp_replace(c.relname, '[a-zA-Z]+[a-zA-Z]+(_[a-zA-Z0 -9]+)?', '', 'g')

是一个生成SQL输出的字符串,如何在该语句的同一行进行eval?

想要的输出是:

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

谢谢!

【问题讨论】:

  • 为什么需要是单个查询?
  • 因为我需要创建一个动态语句来影响原始语句以执行嵌套连接或子选择。

标签: regex postgresql dynamic-sql


【解决方案1】:

如果这些是serialidentity 列,最好使用pg_get_serial_sequence() 来获取表的列与其序列之间的链接。

您实际上可以使用query_to_xml() 在 SQL 语句中运行动态 SQL

如果我需要将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;

这里的动态部分是对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>

使用 xpath() 从 XML 值中提取该值并转换为一个数字,然后在最终 SELECT 中使用该数字以实际调用setval()

具有多个 CTE 的嵌套仅用于使每个部分更具可读性。

同样的方法可以例如习惯了find the row count for all tables

关于query_to_xml() 工作原理的一些background

【讨论】:

  • 这个想法很棒,但概念是如何调用动态 sql 结果集作为原始语句的 stament 的一部分。
  • @FabioPalm:正如我所解释的那样,这就是query_to_xml()。如果您需要从中提取多个值,则需要使用例如xmltable()
  • 可以从 xmltable 函数中执行内部函数吗?
猜你喜欢
  • 2021-01-28
  • 1970-01-01
  • 1970-01-01
  • 2012-11-14
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多