【问题标题】:Execute query string and get result with varying number of columns执行查询字符串并获得具有不同列数的结果
【发布时间】:2021-01-29 03:46:08
【问题描述】:

我正在尝试将相关值列表转换为相关矩阵。
但执行字符串查询后我无法获得结果。

列表/表格(命名为 corrtemp)是这样的:

| name | colname | value |
| ---- | ------- | ----- |
| a    | a       | 1     |
| a    | b       | 0.5   |
| a    | c       | 0.3   |
| b    | a       | 0.5   |
| b    | b       | 1     |
| b    | c       | 0.2   |
| c    | a       | 0.3   |
| c    | b       | 0.2   |
| c    | c       | 1     |

输出应该是这样的:

| name |  a  |  b  |  c  |
| ---- |-----| --- | --- |
| a    |  1  | 0.5 | 0.3 |
| b    | 0.5 |  1  | 0.2 |
| c    | 0.3 | 0.2 |  1  |

不同名称的数量未知。所以我循环生成一个字符串查询。我想执行它并在结果控制台中获取查询结果。目前,我的代码是这样的:

do $$
declare 
    i integer := 0;
     sql0 varchar := 'SELECT DISTINCT temp0.name, cor0.value AS '||(SELECT DISTINCT name FROM corrtemp LIMIT 1)||' FROM corrtemp AS temp0'||chr(13);
     sql1 varchar := 'left JOIN corrtemp AS cor0 ON cor0.colname = temp0.name AND cor0.name = ''a'''||chr(13);
     sql2 varchar := 'WITH temp';
     sql4 varchar;
begin
    sql4 := sql0 || sql1 ||chr(13);
    i := i + 1;
    while i < (SELECT COUNT(DISTINCT name) FROM corrtemp) loop
        sql4 := chr(13)|| 
                sql2|| 
                CAST(i AS VARCHAR(5)) || 
                ' AS('||
                chr(13)||
                sql4||
                ')' ||
                'SELECT temp'|| CAST(i AS VARCHAR(5)) || '.*, cor'|| CAST(i AS VARCHAR(5)) ||'.value AS '||(SELECT DISTINCT name FROM corrtemp LIMIT 1 OFFSET i)||' FROM  temp'|| CAST(i AS VARCHAR(5))||chr(13)||
                'left JOIN corrtemp AS cor'|| CAST(i AS VARCHAR(5)) ||  ' ON cor'|| CAST(i AS VARCHAR(5)) || '.colname = temp'|| CAST(i AS VARCHAR(5)) || '.name AND cor'|| CAST(i AS VARCHAR(5)) || '.name = '''|| (SELECT DISTINCT name FROM corrtemp LIMIT 1 OFFSET i)||''''||chr(13);
        i := i + 1;
        end loop;
end$$

我在do 中尝试了EXECUTE sql4,它只在信息控制台中返回“OK”。

我需要在结果控制台中显示查询结果,就像在简单地运行SELECT * FROM corrtemp 之后一样。

【问题讨论】:

  • 我正在考虑使用CREATE OR REPLACE FUNCTION corrsql() RETURNS TABLE,但我无法决定表格的列数。
  • 就像已经评论的那样,SQL 要求在执行时知道返回类型。结果类型不能是完全动态的。也许您知道可能的不同名称的最大值,这是一个合理的数字?
  • @ErwinBrandstetter 是的,我能够知道不同名称的数量。每次调用函数时都应该允许更改名称和名称的数量。

标签: sql postgresql plpgsql dynamic-sql


【解决方案1】:

不幸的是DO 语句没有任何输入/输出的可能性。 DO 语句内可以更改数据,但不能使用DO 语句得到任何结果。

【讨论】:

  • 我尝试创建函数返回 sth (table/setof record)。我现在面临的问题是我无法确定列名和列类型。两种方式都需要这些信息来显示结果表。
  • 你也不能使用函数进行交叉表,因为在执行之前必须知道结果的结构。游标有技巧 - okbob.blogspot.com/2008/08/… 或者如果你使用 psql 客户端,那么你可以使用 \crosstabview 命令。
  • 这里是我面临的现实: 1,由于技术限制,我需要一个可以直接输出关联表的查询。 2,我无法知道列数和列名,这就是为什么我编写了一个while循环来为我拥有的任何相关列表创建查询字符串。我读过你的博客。这是惊人的。但是还是需要指定输出表的col名吧?
  • @sh12121212:如果不让服务器知道每列的编号、名称和数据类型在实际运行查询之前,就无法运行 SQL 语句.如果您的前端可以处理 blog.sql-workbench.eu/post/pivot-alternatives,您可以将“动态部分”聚合到 JSON 列中
  • @a_horse_with_no_name 我试过json,当函数json_populate_recordset让我定义表结构时卡住了。 ;-)
【解决方案2】:

我尝试创建函数。它不起作用。代码如下:

CREATE FUNCTION list2matrix() RETURNS setof record LANGUAGE plpgsql AS $$
declare 
   i integer := 0;
  sql0 varchar := 'SELECT DISTINCT temp0.name, cor0.value AS '||(SELECT DISTINCT name FROM corrtemp LIMIT 1)||' FROM corrtemp AS temp0'||chr(13);
  sql1 varchar := 'left JOIN corrtemp AS cor'|| CAST(i AS VARCHAR(5)) ||  ' ON cor'|| CAST(i AS VARCHAR(5)) || '.colname = temp'|| CAST(i AS VARCHAR(5)) || '.name AND cor'|| CAST(i AS VARCHAR(5)) || '.name = '''|| (SELECT DISTINCT name FROM corrtemp LIMIT 1 OFFSET i)||''''||chr(13);
  sql2 varchar := 'WITH temp';
  sql3 varchar := 'SELECT temp'|| CAST(i AS VARCHAR(5)) || '.*, cor'|| CAST(i AS VARCHAR(5)) ||'.value AS '||(SELECT DISTINCT name FROM corrtemp LIMIT 1 OFFSET i)||' FROM  temp'|| CAST(i AS VARCHAR(5))||chr(13) ;
  sql4 varchar;
begin
   sql4 := sql0 || sql1 ||chr(13);
  i := i + 1;
   while i < (SELECT COUNT(DISTINCT name) FROM corrtemp) loop
      sql4 := chr(13)|| 
            sql2|| 
        CAST(i AS VARCHAR(5)) || 
        ' AS('||
        chr(13)||
        sql4||
        ')' ||
        'SELECT temp'|| CAST(i AS VARCHAR(5)) || '.*, cor'|| CAST(i AS VARCHAR(5)) ||'.value AS '||(SELECT DISTINCT name FROM corrtemp LIMIT 1 OFFSET i)||' FROM  temp'|| CAST(i AS VARCHAR(5))||chr(13)||
        'left JOIN corrtemp AS cor'|| CAST(i AS VARCHAR(5)) ||  ' ON cor'|| CAST(i AS VARCHAR(5)) || '.colname = temp'|| CAST(i AS VARCHAR(5)) || '.name AND cor'|| CAST(i AS VARCHAR(5)) || '.name = '''|| (SELECT DISTINCT name FROM corrtemp LIMIT 1 OFFSET i)||''''||chr(13);
    i := i + 1;
     end loop;
         RETURN QUERY EXECUTE sql4;
end$$;

select list2matrix();

它向我发送以下错误消息:

错误:在不能接受集合的上下文中调用的集合值函数

看来我还是得定义表结构,我真的不能,因为相关矩阵总是在变化。

【讨论】:

    猜你喜欢
    • 2023-03-09
    • 1970-01-01
    • 2019-07-31
    • 2013-05-06
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-01-11
    相关资源
    最近更新 更多