具有 EXECUTE 和嵌套格式的动态 SQL

Dynamic SQL with EXECUTE and nested format()

我试着用普通的 CTE(没有 EXECUTE ... FORMAT)做到这一点,我能够做到。 我基本上有一个 table,它有大约 5 列,每列中有一些我想连接的数据,例如 manifest/generate 新列中的一些数据。

我可以做这样的事情并且有效:

WITH cte AS (SELECT *, case 
                        when var1 = '' then ''
                        when var2 = '' then ''
                        else '' end, 'adding_dummy_text_column'
             FROM some_other_table sot
             WHERE sot.type = 'java')

             INSERT INTO my_new_table 
                    SELECT *, 'This is the new column I want to make with some data from my CTE' || c.type
                    FROM cte c;

所以这就像我说的那样有效。我最终会得到一个新的 table,它有一个额外的列,其中有一个硬编码的连接字符串 This is the new column I want to make with some data from my CTE Java

当然,在加载 SELECT 时,CTE 中相应行的 c.type 列中的任何内容都会连接到该字符串。

问题是,一旦我开始使用 EXECUTE...FORMAT 使它更干净并且对来自不同列的 concatenate/combined 不同数据片段有更多的能力(我的数据有点分散格式错误,我正在填充一个全新的 table),就好像 FORMAT 参数或变量无法检测到 CTE table.

我就是这样做的

EXECUTE FORMAT ('WITH cte AS (SELECT *, case 
                        when var1 = %L then %L
                        when var2 = '' '' then '' ''
                        else '' '' end, ''adding_dummy_text_column''
             FROM some_other_table sot
             WHERE sot.type = ''java'')

             INSERT INTO my_new_table 
                    SELECT *, ''This is the new column I want to make with some data from my CTE %I''
                    FROM cte c', 'word1', 'word2', c.type
             );

好的,所以我知道我在这个例子中使用了空字符串 '' ''%L 但我只是想表明我没有任何问题。当我尝试引用我的 CTE 列时,您可以看到我正在尝试进行相同的串联,但通过利用 EXECUTE...FORMAT 并使用 %I 标识符。因此,前 2 个参数很好,它的 c.type 无论我尝试哪一列,都不起作用。此外,我删除了 c 别名并且没有得到任何更好的运气。不过,每当我引用 CTE 上的列时它都是 100%,因为我已经删除了所有这些代码并且没有它它运行得很好。

但是,是的,有什么变通办法吗?我真的很想转换一些数据,现在必须做 ||用于串联。

应该这样做:

EXECUTE format($f$WITH cte AS (SELECT *, CASE
                        WHEN var1 = %L THEN %L
                        WHEN var2 = ' ' THEN ' '
                        ELSE ' ' END, 'adding_dummy_text_column'
             FROM some_other_table sot
             WHERE sot.type = 'java')

             INSERT INTO my_new_table
                    SELECT *, format('This is the new column I want to make with some data from my CTE %%I', c.type)
                    FROM cte c$f$
           , 'word1', 'word2');
  • 两个级别。您需要第二个 format() 由第一个 format().

    连接的动态 SQL 字符串执行
  • 我用 dollar-quoting 进行了简化。参见:

    • Insert text with single quotes in PostgreSQL
  • 嵌套的 % 字符必须通过加倍来转义:%%I。参见:

    • What does %% in PL/pgSQL mean?

生成并执行此 SQL 语句:

WITH cte AS (SELECT *, CASE
                        WHEN var1 = 'word1' THEN 'word2'
                        WHEN var2 = ' ' THEN ' '
                        ELSE ' ' END, 'adding_dummy_text_column'
FROM some_other_table sot
WHERE sot.type = 'java')

INSERT INTO my_new_table
SELECT *, format('This is the new column I want to make with some data from my CTE %I', c.type)
FROM cte c

可以简化和改进为以下等价物:

INSERT INTO my_new_table(co1, col2, ...)  -- provide target column list!
SELECT *
     , CASE WHEN var1 = 'word1' THEN 'word2'
            WHEN var2 = ' ' THEN ' '
            ELSE ' ' END
     , 'adding_dummy_text_column'
     , format('This is the new column I want to make with some data from my CTE %I', sot.type)
FROM   some_other_table sot
WHERE  sot.type = 'java'

关于缺失的目标列列表:

  • Cannot create stored procedure to insert data: type mismatch for serial column

您可以使用一个命令,创建并插入到新的 table!

create table my_new_table as
    select *
            , CASE WHEN var1 = 'hello' THEN 'word2'
                   WHEN var2 = ' ' THEN 'var2 is empty'
                   ELSE ' ' END adding_dummy_text_column
            , format(
                'This is the new column I want to make with some data from my CTE %I', sot.type)
           from some_other_table sot
                where sot.type ='java';