Postgres 中的动态 UNION ALL 查询

Posted

技术标签:

【中文标题】Postgres 中的动态 UNION ALL 查询【英文标题】:Dynamic UNION ALL query in Postgres 【发布时间】:2016-02-18 15:48:03 【问题描述】:

我们正在使用 Postgres / PostGis 连接来获取通过地理服务器发布的数据。

查询现在看起来像这样:

SELECT 
    row_number() over (ORDER BY a.ogc_fid) AS qid, a.wkb_geometry AS geometry
FROM
(
   SELECT * FROM test
   UNION ALL
   SELECT * FROM test1
   UNION ALL
   SELECT * FROM test2
)a

在我们的数据库中,只有有效的 shapefile 将被导入到单个表中,因此使 UNION ALL 部分动态化(循环遍历每个表并生成 UNION ALL 语句)是有意义的。有没有办法以标准的 Postgres 方式执行此操作,或者我是否需要编写一个函数以及语法如何?我对 SQL 很陌生。

shapefile 具有不同的数据结构,只有 ogc_fid 列和 wkb_geometry 列始终可用,我们希望合并数据库中的所有表。

【问题讨论】:

我真的不知道这个 shapefile 是什么,但是你为什么不把所有的东西都导入到一个表中呢?另一种选择是使用表继承 你的问题不是很清楚。所以答案取决于你想做什么。但简单的解决方法是创建一个DYNAMIC QUERY,但您需要一种方法来知道您要加入哪些表 在 shapefile 中,您可以存储地理数据。我们希望避免将所有内容存储在单个表中,因为地理数据的数据结构可能不同,我们希望保留每个文件的所有列以供其他查询使用 @JuanCarlosOropeza - 我更新了我的问题。在这个特定的数据库中,所有表都需要联合 如果你想在每个表中有不同的列,那么你不可能在联合语句中使用它们。 【参考方案1】:

这只是您需要在细节方面特别是语法的一般准则。

你需要创建一个存储过程

为您想要的表名创建一个循环检查information_schema.tables 过滤器

DECLARE    
    rec record;
    strSQL text;
BEGIN

然后为每个表创建一个strSQL

 FOR rec IN SELECT table_schema, table_name
            FROM information_schema.tables                
 LOOP
     strSQL := strSQL || 'SELECT ogc_fid, wkb_geometry FROM ' || 
               rec.table_schema || '.' || rec.table_name || ' UNION ';
 END LOOP;

-- have to remove the last ' UNION ' from strSQL    

strSQL := 'SELECT  row_number() over (ORDER BY a.ogc_fid) AS qid,
         a.wkb_geometry AS geometry FROM (' || strSQL || ')';

EXECUTE strSQL;

【讨论】:

@ClodoaldoNeto 是什么让你认为这是 SQL Server? 感谢您的回答 - 这对您有很大帮助。我最终使用了 UNION ALL。顺便提一句。我认为有一个小错误:应该是“rec.table_name ||”而不是“rec.table_name +” 你说得对,有时我会混合使用 sql server 和 postgres syntaxis。 @JuanCarlosOropeza 我正在尝试使用您的解决方案,但在记录或接近记录时出现语法错误。有什么想法吗? 从字符串中删除最后一个 UNION 可以这样工作strSQL := left(strSQL, -6);【参考方案2】:

一种解决方案是使用row_to_json() 将其余列序列化为json。 (从 PostgreSQL9.2 开始可用)。 对于 PG9.1(及更早版本),您可以使用 hstore,但请注意所有值都转换为文本。

为什么要序列化?无法union 列数不同的行,或者联合查询之间的数据类型不匹配。

我创建了一个简单的例子来说明:

--DROP SCHEMA testschema CASCADE;
CREATE SCHEMA testschema;

CREATE TABLE testschema.test1 (
    id integer,
    fid integer,
    metadata text
);

CREATE TABLE testschema.test2 (
    id integer,
    fid integer,
    city text,
    count integer
);

CREATE TABLE testschema.test3 (
    id integer,
    fid integer
);


INSERT INTO testschema.test1 VALUES (1,   4450, 'lala');
INSERT INTO testschema.test2 VALUES (33,  6682, 'London', 12345);
INSERT INTO testschema.test3 VALUES (185, 8991);


SELECT 
    row_number() OVER (ORDER BY a.fid) AS qid, a.*
FROM
(
    SELECT id, fid, row_to_json(t.*) AS jsondoc FROM testschema.test1 t
    UNION ALL 
    SELECT id, fid, row_to_json(t.*) AS jsondoc FROM testschema.test2 t
    UNION ALL 
    SELECT id, fid, row_to_json(t.*) AS jsondoc FROM testschema.test3 t    
) a

选择输出:

qid  id    fid    jsondoc
1;   1;    4450;  ""id":1,"fid":4450,"metadata":"lala""
2;   33;   6682;  ""id":33,"fid":6682,"city":"London","count":12345"
3;   185;  8991;  ""id":185,"fid":8991"

【讨论】:

以上是关于Postgres 中的动态 UNION ALL 查询的主要内容,如果未能解决你的问题,请参考以下文章

如何在 postgres 中对相同的 CTE 表达式执行 UNION ALL?

union all 效率问题

Bigquery 使用 Union All 和通配符删除查询

union和union all用法

Union和Union All 的区别

mysql中union与union all的区别