如何在 SQL WITH 语句中使用 table?

How to use a table in SQL WITH statement?

我试图在问题底部的 SQL 语句中使用预先存在的 table,而不是在 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 的 table,其中包含 poly_idgeom 列,与上面创建的完全一样。我怎样才能将我预先存在的 polys table 插入到这个 SQL 语句中(即我将使用什么语法)?

我已尝试使用以下方法添加预先存在的 polys table:

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;

嗯,这个问题对我来说不是 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 创建某种临时表,然后创建...

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

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

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 中定义的不同“临时”table,但最后一句话前面没有 ,

因此,要从 CTE 创建 table,语法为:

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 子句创建 table 与其他情况相同:

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 的 table,例如前面的示例所示,您可以替换

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