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?