我正在参加编程挑战。我提到这一点不是,因为我需要有关挑战本身的帮助 - 我已经设计了一个解决方案,但我找不到一种方法使该解决方案能够适应 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..)
但是我找不到使用原始语句的方法:
我读过很多关于运行 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 发出的字符串中的 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;