【问题标题】:Postgresql: cannot get result using sub-query at FROM ... placePostgresql:无法在 FROM ... 位置使用子查询获得结果
【发布时间】:2015-08-09 23:32:20
【问题描述】:

我想要完成的是通过内部 SQL 中的所有表获取 sendercompidtargetcompidmsgtype 的所有唯一组合的聚合数据。

我希望在结果输出中有 2000 万到 4000 万个不同的行。

我无法在 Postgresql 8.3.13 上成功运行下一个查询:

SELECT 
    sendercompid, targetcompid, count(msgtype), msgtype 
FROM 
    (SELECT table_name 
     FROM information_schema.tables 
     WHERE table_catalog = 'test' 
       AND table_schema = 'msg' 
       AND (table_name like 'fix_aee_20121214%') OR 
           (table_name like 'fix_aee2_20121214%')
   ) 
WHERE 
    (sendercompid LIKE '%201%') OR 
    (targetcompid LIKE '%201%') 
GROUP BY 
    sendercompid, targetcompid, msgtype ;

如果此选择在 2 上拆分:外部和内部,则: inner 将提供表列表,而 outer 将从每个表中进行选择和分组。

如果我将这两个 SQL 作为一个运行,我会收到来自 pgsql db 的别名错误

错误:FROM 中的子查询必须有别名

我尝试使用别名,但这个错误并没有消失。

有什么想法我在那里想念的吗?

谢谢。

【问题讨论】:

  • 不能动态定义“from”部分,查询中涉及的所有表名必须在语句执行前知道。

标签: postgresql


【解决方案1】:

FROM 不像你想象的那样工作。子选择与任何其他查询一样工作:它产生一组行。外部 SELECT 与这些行一起工作,就好像它们是一个表一样。除此之外没有什么特别的魔法。它不知道您返回的值是表名,并且不会这样对待它们。

您可能可以使用目录表来完成您想要的事情,但这会很复杂而且很麻烦。

由于您的子表似乎是基于日期的分区,我认为您真正想要使用的是 Postgres 中内置的分区支持,描述为 in these docs。本质上,您的分区继承自父表,并且您为每个子表设置范围约束。当您从启用了约束排除的父表中查询时,Postgres 会自动选择适当的分区。

【讨论】:

  • 非常感谢您的详细解答。不幸的是,我没有设置分区,我不能这样做。数据库正在填充我负责的应用程序,所以我只能从表中读取,仅此而已。事实上,FROM 子句中的所有表在数据结构上都是相同的,只是名称中的日期不同,因此它们可能是一个主表的子表。不幸的是,事实并非如此。
【解决方案2】:

您可以使用动态 SQL “运行”此类查询。这个想法 - 在 PL\pgSQL 过程和EXECUTE 中使用表名作为字符串形成正确的查询。比如:

CREATE OR REPLACE FUNCTION public.function1 (
)
RETURNS TABLE (
  "field1" NUMERIC,
  "field2" NUMERIC,
  ...
) AS
$body$
BEGIN
 RETURN EXECUTE 'SELECT * FROM '|| (SELECT table_name from information_schema.tables 
              where table_catalog = 'test' AND 
                    table_schema='msg' AND
                    (table_name like 'fix_aee_20121214%') OR 
                    (table_name like 'fix_aee2_20121214%')); 
END;
$body$
LANGUAGE 'plpgsql';

然后使用类似的东西:

SELECT sendercompid, targetcompid, count(msgtype), msgtype 
       FROM  function1
       WHERE (sendercompid LIKE '%201%') OR 
             (targetcompid LIKE '%201%') 
       GROUP BY sendercompid, targetcompid, msgtype ;

或者您可以创建带有完整查询和一些参数的函数来构建WHERE 子句。

详情:EXECUTE

【讨论】:

  • 谢谢伊戈尔。不幸的是,这对我不起作用,我需要与“table_name like”动态部分。所以我需要为每个日期创建新程序。这会产生额外的开销。
  • @Daniel 无需为每个日期创建程序。只需将日期作为参数传递给函数。类似table_name like 'fix_aee_'||to_char(date_param,'yyyymmdd')||'%'
  • @Daniel 然后SELECT * FROM function_name(CURRENT_DATE)
【解决方案3】:

如果这只是一个概念,那么:

  1. ERROR: subquery in FROM must have an alias
  2. 没有sendercompid, targetcompid, count(msgtype), msgtype 列来自何处的信息。

    SELECT sendercompid, targetcompid, count(msgtype), msgtype from ( 从 information_schema.tables 中选择表名 其中 table_catalog = 'test' AND table_schema='msg' 和 (table_name like 'fix_aee_20121214%')或 (table_name 像 'fix_aee2_20121214%') ) 一个 WHERE (sendercompid LIKE '%201%') 或 (targetcompid LIKE '%201%') GROUP BY sendercompid, targetcompid, msgtype ;

【讨论】:

    【解决方案4】:

    为子查询使用别名。最好为所有表设置别名以避免混淆。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2017-11-18
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-06-22
      • 2021-05-08
      • 1970-01-01
      相关资源
      最近更新 更多