【问题标题】:How to use a table in SQL WITH statement?如何在 SQL WITH 语句中使用表?
【发布时间】:2020-11-17 04:47:46
【问题描述】:

我试图在问题底部的 SQL 语句中使用预先存在的表,而不是在 SQL 语句中生成的数据。目前,有一些数据是使用以下方法生成的:

WITH polys(poly_id, geom) AS (VALUES  (1, 'POLYGON((1 1, 1 5, 4 5, 4 4, 2 4, 2 2, 4 2, 4 1, 1 1))'::GEOMETRY),
                                      (2, 'POLYGON((6 6, 6 10, 8 10, 9 7, 8 6, 6 6))'::GEOMETRY)),

但是,假设我已经有一个名为polys 的表,其中包含poly_idgeom 列,与上面创建的完全一样。如何将我预先存在的polys 表插入此 SQL 语句(即我将使用什么语法)?

我尝试了以下方法来添加一个预先存在的polys 表:

CREATE TABLE polys_pts AS
WITH polys(poly_id, geom) AS, 

出现以下错误:

ERROR:  syntax error at or near ","
LINE 2: WITH polys(poly_id, geom) AS,
                                    ^

完整代码:

CREATE TABLE polys_pts AS
WITH polys(poly_id, geom) AS (VALUES  (1, 'POLYGON((1 1, 1 5, 4 5, 4 4, 2 4, 2 2, 4 2, 4 1, 1 1))'::GEOMETRY),
                                      (2, 'POLYGON((6 6, 6 10, 8 10, 9 7, 8 6, 6 6))'::GEOMETRY)),
pnt_clusters AS (SELECT  polys.poly_id,
      CASE
          WHEN ST_Area(polys.geom)>9 THEN ST_ClusterKMeans(pts.geom, 8) OVER(PARTITION BY polys.poly_id) 
          ELSE ST_ClusterKMeans(pts.geom, 2) OVER(PARTITION BY polys.poly_id) 
      END AS cluster_id, pts.geom FROM polys,
          LATERAL ST_Dump(ST_GeneratePoints(polys.geom, 1000, 1)) AS pts),
centroids AS (SELECT cluster_id, ST_PointOnSurface(ST_collect(geom)) AS geom FROM pnt_clusters GROUP BY poly_id, cluster_id),
neg_buffer AS (SELECT poly_id, (ST_Buffer(geom, -0.4, 'endcap=flat join=round')) geom FROM polys GROUP BY poly_id, polys.geom),
neg_buffer_pts_out AS (SELECT a.cluster_id, (a.geom) geom FROM centroids a WHERE EXISTS (SELECT 1 FROM neg_buffer b WHERE ST_Intersects(a.geom, b.geom))),
neg_buffer_pts_in AS (SELECT a.cluster_id, (a.geom) geom FROM centroids a WHERE NOT EXISTS (SELECT 1 FROM neg_buffer b WHERE ST_Intersects(a.geom, b.geom))),
snap_pts_clusters_in AS (SELECT DISTINCT ST_ClosestPoint(ST_ExteriorRing(a.geom), b.geom) AS geom FROM neg_buffer a, neg_buffer_pts_in b),
node_pts AS (SELECT ST_StartPoint(ST_ExteriorRing(geom)) geom FROM neg_buffer),
snap_pts AS (SELECT b.cluster_id, a.geom FROM snap_pts_clusters_in a JOIN centroids b ON ST_DWithin(a.geom, b.geom, 0.4))
SELECT  a.cluster_id, (a.geom) geom FROM snap_pts a WHERE NOT EXISTS (SELECT 1 FROM node_pts b WHERE ST_Intersects(a.geom, b.geom))
UNION SELECT c.cluster_id, (c.geom) geom FROM neg_buffer_pts_out c ORDER BY cluster_id;

【问题讨论】:

    标签: sql postgresql postgis common-table-expression


    【解决方案1】:

    我不确定理解你的问题,所以我给你一个广泛的答案。

    您必须使用create a table from a query

    CREATE TABLE foo AS
        SELECT * FROM my_table;
    

    CTEs 构建为:

    WITH 
        tmp1 AS (
            SELECT * from my_table1
        ), -- commna
    
        tmp2 AS (
            SELECT * from my_table2
        )
    
    SELECT * from tmp1 JOIN tmp2 ON tmp1.id = tmp2.id -- no comma
    ;
    

    请注意,, 用于分隔 CTE 中定义的不同“临时”表,但最后一句前面没有 ,

    因此,要从 CTE 创建表,语法将是:

    CREATE TABLE foo AS
        WITH 
            tmp1 AS (
                SELECT * from my_table1
            ),
    
            tmp2 AS (
                SELECT * from my_table2
            )
    
        SELECT * from tmp1 JOIN tmp2 ON tmp1.id = tmp2.id -- no comma
    ;
    

    VALUES 子句创建表与其他情况相同:

    CREATE TABLE polys2 AS
        VALUES
            (1, 'POLYGON((1 1, 1 5, 4 5, 4 4, 2 4, 2 2, 4 2, 4 1, 1 1))'::GEOMETRY),
            (2, 'POLYGON((6 6, 6 10, 8 10, 9 7, 8 6, 6 6))'::GEOMETRY)
    ;
    

    如果您已经创建了一个名为 polys2 的表,例如前面的示例所示,您可以替换

    CREATE TABLE polys_pts AS
        WITH 
            polys(poly_id, geom) AS (
                VALUES
                    (1, 'POLYGON((1 1, 1 5, 4 5, 4 4, 2 4, 2 2, 4 2, 4 1, 1 1))'::GEOMETRY),
                    (2, 'POLYGON((6 6, 6 10, 8 10, 9 7, 8 6, 6 6))'::GEOMETRY)),
             pnt_clusters AS (SELECT  polys.poly_id, ...
    

    CREATE TABLE polys_pts AS
        WITH 
            polys(poly_id, geom) AS (
                SELECT poly_id, geom FROM polys2
             ),
             pnt_clusters AS (SELECT  polys.poly_id, ...
    

    【讨论】:

    • 很抱歉给您带来了困惑——我仍在努力了解 SQL 和 Postgres。在我的例子中,我试图用 postgres 数据库中名为 polys2 的表替换 FROM(VALUES... 部分。 polys2 与使用 FROM(VALUES... 创建的临时表相同
    【解决方案2】:

    嗯,这个问题对我来说不是 100% 清楚 - ...我不熟悉 postgresql 的特性,但我的第一个赌注是尝试

    WITH polys(...) AS (...), 
         pnt_clusters AS (...)
    CREATE polys_pts AS (
         SELECT .. 
         FROM polys... etc.
    )
    

    但我想这是不允许的,因为 WITH 仅与 DML 语句一起使用(数据操作与 CREATE 等数据定义 (DDL) 语句不同)

    所以.. 我的下一个赌注是尝试使用您在 WITH 子句中定义的 polys 和 pnt_clusters,内联在 SELECT 语句中,因为

    WITH a AS (
       SELECT x, y FROM z
    )
    SELECT * 
    FROM a
    

    一样
    SELECT * 
    FROM (
       SELECT x, y 
       FROM z
    ) AS a
    

    好吧,否则我会将这个过程分成两个步骤 - 首先为 polys 和 pnt_clusters 创建某种临时表,然后再创建...

    【讨论】:

      【解决方案3】:

      CTE的定义必须是完整的语句,所以必须使用

      WITH polys(poly_id, geom) AS (
         SELECT *
         FROM (VALUES
                 (1, 'POLYGON((1 1, 1 5, 4 5, 4 4, 2 4, 2 2, 4 2, 4 1, 1 1))'::GEOMETRY),
                 (2, 'POLYGON((6 6, 6 10, 8 10, 9 7, 8 6, 6 6))'::GEOMETRY)
              ) AS p(p, g)
      )
      

      【讨论】:

        猜你喜欢
        • 2013-03-12
        • 1970-01-01
        • 1970-01-01
        • 2017-07-12
        • 2020-07-02
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多