【问题标题】:Function to loop through and select data from multiple tables循环并从多个表中选择数据的函数
【发布时间】:2014-08-28 09:53:55
【问题描述】:

我是 Postgres 的新手,我有一个包含多个相同结构表的数据库。我需要从每个表中选择符合特定条件的数据。

我可以用一堆UNION 查询来做到这一点,但是我需要搜索的表的数量会随着时间的推移而改变,所以我不想这样硬编码。我一直在尝试开发一个函数,它将遍历特定的表(它们有一个共同的命名约定)并返回一个记录表,但是当我查询该函数时我没有得到任何结果。功能代码如下:

CREATE OR REPLACE FUNCTION public.internalid_formaltable_name_lookup()
  RETURNS TABLE(natural_id text, name text, natural_id_numeric text) AS
$BODY$
DECLARE
    formal_table text;
begin
  FOR formal_table IN
    select table_name from information_schema.tables
    where table_schema = 'public' and table_name like 'formaltable%'
  LOOP
    EXECUTE 'SELECT natural_id, name, natural_id_numeric
             FROM ' || formal_table || 
           ' WHERE natural_id_numeric IN (
                select natural_id_numeric from internal_idlookup
                where internal_id = ''7166571'')';
    RETURN NEXT;
 END LOOP;
 Return;
END;
$BODY$
  LANGUAGE plpgsql;

我在尝试使用该函数时没有收到任何错误,但它没有返回任何行:

SELECT * From internalid_formaltable_name_lookup();

知道我哪里出错了吗?

【问题讨论】:

  • 你不能创建一个父表并继承子表,这样如果它们的结构相似,你就可以只查询一个表吗?
  • 你在“RETURN NEXT expr”中的表达也是空的。

标签: postgresql for-loop plpgsql dynamic-sql set-returning-functions


【解决方案1】:
CREATE OR REPLACE FUNCTION public.internalid_formaltable_name_lookup()
  RETURNS TABLE(natural_id text, name text, natural_id_numeric text)
  LANGUAGE plpgsql AS
$func$
DECLARE
   formal_table text;
BEGIN
   FOR formal_table IN
      SELECT quote_ident(table_name)
      FROM   information_schema.tables
      WHERE  table_schema = 'public'
      AND    table_name LIKE 'formaltable%'
   LOOP
      RETURN QUERY EXECUTE
      'SELECT t.natural_id, t.name, t.natural_id_numeric
       FROM   internal_idlookup i 
       JOIN   public.' || formal_table || ' t USING (natural_id_numeric)
       WHERE  i.internal_id = 7166571';   -- assuming internal_id is numeric
   END LOOP;
END
$func$;

您必须使用RETURN QUERY EXECUTE 来返回每个行集
EXECUTE,然后是RETURN NEXT,完全不像您所期望的那样 .

您需要清理标识符。我在这里使用quote_ident()。否则您的查询将被非标准标识符破坏并允许 SQL 注入!

将您的col IN (sub-select) 转换为更高效的JOIN

这与使用a bunch of UNION queries 略有不同。它确实删除重复的行,实际上就像UNION ALL一样工作。

就个人而言,我宁愿在系统目录pg_class 或系统视图pg_tables 上构建它。详情:

然后您可以使用pg_class.oid::regclass 自动转义和模式限定表名。详情:

但这取决于您的要求和...品味的细节。

【讨论】:

  • 感谢您指出使用quote_ident()。我使用quote_literal(),因为前者添加双引号(“),而后者添加单引号(')。
猜你喜欢
  • 1970-01-01
  • 2020-06-23
  • 2014-01-05
  • 1970-01-01
  • 1970-01-01
  • 2021-02-06
  • 1970-01-01
  • 2020-07-04
相关资源
最近更新 更多