在普通 SQL 语句中执行动态生成的 Postgres 13 SQL(返回结果集)

问题描述 投票:0回答:1

我正在参加编程挑战。我提到这一点不是,因为我需要有关挑战本身的帮助 - 我已经设计了一个解决方案,但我找不到一种方法使该解决方案能够适应 Postgres 施加的技术限制

我相信这个挑战需要动态查询来解决,因为单个 SQL 查询必须产生一个输出,其中每次运行时输出的列数和名称都不同。该挑战有 3 个场景,相同的查询必须解决每个场景,但预期作为输出的列是由输入数据中的行驱动的,每个场景各不相同 - 如果不构建动态字符串,我无法看到如何解决这个问题执行它。

本质上如果输入数据是:

  CountOfSales, ProductName
  1,            Chocolate
  2,            Cola

那么输出需要是

  Chocolate, Cola, Total
  1,         2,    3

如果输入的是

  CountOfSales, ProductName
  100,          Burgers
  200,          Fries
  300,          Shakes

那么输出需要是

  Burgers, Fries, Shakes, Total
  100,     200,   300,    600

真正的挑战比这更复杂,因为我编写的构建动态 SQL 的查询也是如此,但这应该足以解释我的问题。

假设我创建了一个查询来编写生成这些结果的 SQL;本质上就像:

  SELECT CONCAT('SELECT ', STRING_AGG(CONCAT(CountOfSales, ' AS ', ProductName), ','), ', ', SUM(CountOfSales), ' as Total FROM Input') FROM Input

运行此命令的输出将是:

  --when executed against test 1
  'SELECT 1 as Chocolate, 2 as Cola, 3 as Total'

  --executed against test 2
  'SELECT 100 as Burgers, 200 as Fries, 300 as Shakes, 600 as Total'

也就是说,当我编写的挑战 SQL 运行时,它会生成一个完整、有效的 SQL 字符串,可以运行该字符串来解决该场景的挑战

当我将这些生成的查询复制并粘贴到运行框中并运行它们时,它们解决了各自的场景(第一个通过测试 1 但未通过测试 2,第二个通过测试 2 但未通过测试 1..)

但是我找不到使用原始语句的方法:

  1. 它运行生成一个包含解决挑战所需的 SQL 的字符串
  2. 然后将生成的 SQL 执行到结果集
  3. 返回结果集以通过测试

我读过很多关于运行 PG 动态 SQL 的问题,其中有“使用 do 块”之类的建议,但添加了如下代码:

DO $$
DECLARE q TEXT;
BEGIN
  q:= (SELECT CONCAT('SELECT ', STRING_AGG(CONCAT(Amount, ' AS ', product_id), ','), ', ', SUM(amount), ' as Total') FROM Sales);

  EXECUTE q INTO x;
  
  SELECT * FROM x;
END $$;

我明白了

PG::SyntaxError: 错误: 位于或附近未终止的美元引号字符串 “$$ 声明 q 文本;

我读到在线小提琴类型网站可能不喜欢 $$ 字符串,所以我将其交换为

'
字符串,里面到处都是双倍的
''
;该错误只是抱怨未终止的
'
字符串

我尝试没有障碍:

EXECUTE (SELECT CONCAT('SELECT ', STRING_AGG(CONCAT(Amount, ' AS ', product_id), ','), ', ', SUM(amount), ' as Total') FROM Sales) INTO x;

(

附近的语法错误

我尝试将

(SELECT CONCAT('SELECT ', STRING_AGG(CONCAT(Amount, ' AS ', product_id), ','), ', ', SUM(amount)
的结果赋值给一个变量并执行该变量;那里也没有欢乐

我找到了创建执行 SQL 的函数的建议:

CREATE OR REPLACE FUNCTION public.exec(
text)
RETURNS SETOF RECORD
LANGUAGE 'plpgsql'
AS $BODY$
BEGIN 
    RETURN QUERY EXECUTE $1 ; 
END 
$BODY$;


SELECT * FROM exec(SELECT CONCAT('SELECT ', STRING_AGG(CONCAT(Amount, ' AS ', product_id), ','), ', ', SUM(amount), ' as Total') FROM Sales)

或者尝试将生成的 SQL 放入变量中,然后

exec()
...他们都没有成功,总是出现一些语法错误

所有这些建议感觉像是应该在 PLPGSQL 块中执行的事情,但我感觉我没有那样的想法;我想我有一个简单的 SQL 语句..我可以运行如下查询:

CREATE EXTENSION IF NOT EXISTS tablefunc;

SELECT ... FROM crosstab...

但也许这也只是一个简单的语句,尽管存在非 SELECT 操作

我还没有尝试过query-to-xml或类似的方法,因为我认为这仍然不好,因为你无法将XML提取回具有不同列nmaes的表格结果集,而没有对你执行的查询的一些动态元素进行提取

需要明确的是,我并不是在挑战本身上寻求帮助;而是在寻求帮助。我已经编写了一个复杂的查询,该查询能够形成可以通过挑战测试的动态 SQL。我正在努力解决的是在构建查询字符串后立即执行它

如何运行包含在 SQL 发出的字符串中的 SQL,而不访问 PGPLSQL 上下文?

sql postgresql dynamic-sql
1个回答
0
投票

如何运行包含在 SQL 发出的字符串中的 SQL,而不访问 PGPLSQL 上下文?

我们可以使用

DO
块在语句中创建 PGPLSQL 上下文

这是错误的:

DO $$
DECLARE q TEXT;
BEGIN
  q:= (SELECT CONCAT('SELECT ', STRING_AGG(CONCAT(Amount, ' AS ', product_id), ','), ', ', SUM(amount), ' as Total') FROM Sales);

  EXECUTE q INTO x;
  
  SELECT * FROM x;
END $$;

这本来可以解决:

DO $$
DECLARE q TEXT;
BEGIN
  q:= (SELECT CONCAT('CREATE TABLE temp AS SELECT ', STRING_AGG(CONCAT(Amount, ' AS ', product_id), ','), ', ', SUM(amount), ' as Total') FROM Sales);

  EXECUTE q;
  
END $$;

SELECT * FROM temp;
© www.soinside.com 2019 - 2024. All rights reserved.