【问题标题】:Handle result when dynamic SQL is in a loop动态 SQL 在循环中时处理结果
【发布时间】:2017-09-18 15:18:34
【问题描述】:

我有一堆表有一个“stat”列(stat 表示状态;-)

我想要每个统计数据的计数,看看吧!

我的桌子是这样的

create table a (
   a_id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
   a_stat status_t
);
create table b (
   b_id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
   b_stat status_t
);

status_t 是一个枚举。

所以我这样做了:

DO $$
DECLARE
  tableName RECORD;
  result RECORD;
BEGIN
  SET SEARCH_PATH = projet, public;

  FOR tableName IN SELECT
             c.relname,
             a.attname
           FROM pg_class AS c
             INNER JOIN pg_attribute AS a ON a.attrelid = c.oid
           WHERE a.attname LIKE '%stat' AND c.relkind = 'r' LOOP

      EXECUTE format('SELECT %I, count(%I) FROM %I GROUP BY %I',
                     tableName.attname, tableName.attname, tableName.relname, tableName.attname) INTO result;
      SELECT * FROM result;
  END LOOP;
END;
$$;

有些事情我认为我在这里做得不好。

  • 也许有更好的格式
  • 我无法选择 RECORD,我认为数据类型不好(但无法弄清楚我应该使用哪种类型)
  • for 循环中的选择不是一个好主意(我认为?)但我没有找到如何将result 放入结果数组中,并在 for 循环之后显示它。

如何正确地做到这一点?

【问题讨论】:

    标签: postgresql count plpgsql dynamic-sql


    【解决方案1】:

    您不能从DO 命令返回。您可以提出通知或写信到临时表来解决此问题。而是使用适当的功能。像这样:

    CREATE OR REPLACE FUNCTION foo()
      RETURNS TABLE (sch_name text, tbl_name text, col_name text, row_count_notnull int8) AS
    $func$
    DECLARE
       _sch text;
       _tbl text;
       _col text;
    BEGIN
      FOR _sch, _tbl, _col IN
          SELECT c.relnamespace::regnamespace, c.relname, a.attname
          FROM   pg_class     c
          JOIN   pg_attribute a ON a.attrelid = c.oid
          WHERE  c.relnamespace = ANY ('{projet, public}'::regnamespace[])  -- project?
          AND    c.relkind = 'r'           -- only regular tables
          AND    a.attname LIKE '%\_stat'  -- a_stat, b_stat
          AND    a.attnum > 0              -- only user columns (redundant here)
          AND    NOT a.attisdropped        -- exclude dropped columns
       LOOP
          RETURN QUERY EXECUTE format(
             'SELECT $1, $2, $3, count(%I) FROM %I.%I GROUP BY 1'
           , _col, _sch, _tbl)
          USING _sch, _tbl, _col;
       END LOOP;
    END
    $func$  LANGUAGE plpgsql;
    

    呼叫:

    SELECT * FROM foo();
    

    要点:

    • SELECT 不能没有目标 (SELECT * FROM result;),无论是在 DO 命令还是在 plpgsql 函数中。 (您可以使用普通的 SQL 函数,但那里没有循环。)我使用 RETURN QUERY EXECUTE 返回结果。

    • 使用USING 子句将传递给EXECUTE

    • 动态查询中的模式限定表。否则,您可能会不小心查询到错误的表。

    • 不包括您尝试的临时架构(即使您不知道)。如果需要,您可以使用 pg_my_temp_schema() 添加它,但您可能并不想要它:

    相关:

    Search for more examples with dynamic SQL in plpgsql here on SO.

    【讨论】:

    • 谢谢,我想知道我是否可以在 for 循环结束时进行选择,但是您的具有适当功能的解决方案似乎不错,谢谢
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-12-27
    相关资源
    最近更新 更多