简体   繁体   English

Postgres中的动态UNION ALL查询

[英]Dynamic UNION ALL query in Postgres

We are using a Postgres / PostGis connection to get data that is published via a geoserver. 我们正在使用Postgres / PostGis连接来获取通过地理服务器发布的数据。

The Query looks like this at the moment: 目前查询看起来像这样:

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

In our db only valid shapefiles will be imported each in a single table so it would make sense to make the UNION ALL part dynamic (loop over each table and make the UNION ALL statement). 在我们的数据库中,仅将有效的shapefile导入到单个表中,因此使UNION ALL零件动态化(遍历每个表并执行UNION ALL语句)是有意义的。 Is there a way to do this in a standard Postgres way or do I need to write a function and how would the syntax look like? 有没有一种方法可以以标准的Postgres方式执行此操作,或者我需要编写一个函数,语法看起来如何? I am pretty new to SQL. 我对SQL很陌生。

The shapefiles have a different data structure and only the ogc_fid column and the wkb_geometry column are always available and we would like to union all tables from the DB. shapefile具有不同的数据结构,并且只有ogc_fid列和wkb_geometry列始终可用,我们希望从数据库中合并所有表。

This is just general guidelines you need work in the details specially syntaxis. 这只是一般性准则,您需要在细节(特别是语法)方面进行工作。

You need create a store procedure 您需要创建一个存储过程

Create a loop checking information_schema.tables filter for the tablenames you want 创建一个循环,检查所需information_schema.tables的表名的information_schema.tables过滤器

DECLARE    
    rec record;
    strSQL text;
BEGIN

Then create a strSQL with each table 然后为每个表创建一个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;

One solution is to serialize the rest of the columns to json with row_to_json() . 一种解决方案是使用row_to_json()将其余的列序列化为json (available since PostgreSQL9.2). (自PostgreSQL9.2起可用)。 For PG9.1 (and earlier) you can use hstore , but note that all values are cast to text. 对于PG9.1(及更低版本),您可以使用hstore ,但请注意,所有值都强制转换为文本。

Why serialize? 为什么要序列化? It is not possible to union rows where the number of colums vary, or the datatypes do not match between the union queries. 这是不可能的工会行,其中柱的侧向承载力的数量而变化,或数据类型不工会查询之间的匹配。

I created a quick example to illustrate: 我创建了一个简单的示例来说明:

--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

SELECT output: SELECT输出:

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}"

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM