【问题标题】:routing network function issue路由网络功能问题
【发布时间】:2012-11-02 18:41:33
【问题描述】:

this question 开始,我有一些动态 SQL,我正在使用EXECUTE 在 PL/PgSQL 中成功运行,但它似乎没有达到预期的效果。

以下代码是我创建的 plpgsql 函数的一部分。这打算去位于同一轨道上的每个点,并为每个点找到它最近的点,以便最终我将在所有轨道之间创建一个网络。由于某些原因,它无法正常工作。

i代表当前曲目的编号。

 DECLARE
    _r record;
    i int := 0;
    source_geom character varying;
    target_geom character varying;

BEGIN

WHILE i < 3 --DEPENDS ON THE NUMBER OF TRACKS
LOOP

FOR _r IN EXECUTE ' SELECT a.'|| quote_ident(gid_cname) || ' AS id,'
|| ' st_astext( a.'||quote_ident(geo_cname)||') AS source,' 
|| ' st_astext(b.'||quote_ident(geo_cname)||') AS target, ' 
|| ' ST_Distance(a.'||quote_ident(geo_cname) || ' ,  b.'||quote_ident(geo_cname)||') As dist_ft'
|| ' FROM ' || quote_ident (geom_table) ||' AS a INNER JOIN ' || quote_ident(geom_table) || ' As b ON ST_DWithin(a.'||quote_ident(geo_cname)|| ', b.'||quote_ident(geo_cname)|| ',1000)'
|| ' WHERE b.'||quote_ident(gid_cname)|| ' > a.'||quote_ident(gid_cname)|| ' AND b.'||quote_ident(tid_cname)|| ' = '||i|| 'AND a.'||quote_ident(tid_cname)|| ' = '||i|| 
   ' ORDER BY dist_ft '
|| ' Limit 1 '

LOOP

source_geom := _r.source;
target_geom := _r.target;


EXECUTE 'update ' || quote_ident(geom_table) || 
    ' SET source = ''' || source_geom ||''' 
    , target = ''' || target_geom || ''' 
    WHERE ' || quote_ident(gid_cname) || ' =  ' || _r.id;
END LOOP;

i = i + 1;

END LOOP;

RETURN 'OK';
END;

问题是我已经用普通的 sql 测试了查询,并且效果很好。现在由于某种原因在 plpgsql 中它不能正常工作。下面你可以在纯 sql 中找到相同的查询。

SELECT a.ogc_fid AS id, st_astext( a.wkb_geometry) AS source, st_astext(b.wkb_geometry) AS target, ST_Distance(a.wkb_geometry, b.wkb_geometry) As dist_ft
FROM track_points AS a INNER JOIN track_points As b
ON ST_DWithin(a.wkb_geometry , b.wkb_geometry, 1000)
WHERE b.ogc_fid > a.ogc_fid AND b.track_fid = 0 AND a.track_fid = 0 
order by dist_ft

【问题讨论】:

  • 当您说无法正常工作时,究竟是什么意思?错误?没有结果?炸了你的猫?
  • 这意味着它只给出了很少的结果,而不是预期的完整结果,并且没有全部纠正。

标签: sql sql-server postgresql plpgsql


【解决方案1】:

尝试使用format()EXECUTE ... USING,而不是||quote_literal quote_ident

this recent answer

PL/PgSQL 在普通 SQL 中工作时查询失败的常见原因是名称与 PL/PgSQL 中声明的变量发生冲突,但这不适用于动态 EXECUTE 查询,因为它们不能引用在PL/PgSQL函数。

在这种情况下,我认为您在将其转换为动态查询时出错的可能性更大。

尝试替换:

EXECUTE 'SELECT ...'

与:

query_text = 'SELECT ...'
RAISE NOTICE 'About to run: %',query_text;
EXECUTE query_text;

其中query_textDECLAREd 之前的text。查看您生成的查询文本是否真的与您手动运行的查询相匹配。

如果格式更好,调试动态 SQL 会容易得多。尝试更多类似的东西:

EXECUTE format(
  $query$
    SELECT a.%1$I AS id,
           st_astext(a.%2$I) AS source,
           st_astext(b.%2$I) AS target,
           ST_Distance(a.%2$I, b.%2$I) AS dist_ft
    FROM %3$I AS a INNER JOIN %3$I As b
      ON ST_DWithin(a.%2$I , b.%2$I, 1000)
    WHERE b.%1$I > a.%1$I 
      AND b.%4$I = 0 AND a.%4$I = 0 
    ORDER BY dist_ft
    LIMIT %5$L
  $query$,
  gid_cname, geo_cname, geom_table, tid_cname, 1
);

不需要USING 子句,因为没有传递文字参数。

【讨论】:

  • 是的,是的,我已经看到了这个答案。感染,感谢您的建议。
  • 但是,你知道为什么在 plpgsql 中不能正常工作吗?因为我一直试图让它工作几个小时。或者你能准确解释一下 FOR _r IN EXECUTE 它是如何工作的吗?
  • @Ryan 啊,这是你之前的问题。出现了很多问题,所以很容易忘记,尤其是当它不是相同的代码时。如果您提到它/链接到它会有所帮助。正如我所说,在将函数转换为动态 SQL 时可能会出错;尝试更新答案中的建议。
  • @Ryan 还要确保它实际上不起作用;可能是 UPDATEs 实际上是问题所在,因此外部循环查询有效,但您永远看不到任何结果。再次添加RAISE NOTICE 行进行验证。
  • @Ryan All FOR _r IN EXECUTE 所做的是执行查询文本,并为查询返回的每一行将该行存储在记录变量 _r 中,然后执行循环。
【解决方案2】:

我看到了一个非常小的差异:LIMIT 1. 如果你从动态 SQL 中省略它,那会解决它吗?

致以诚挚的问候,

洛克

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2011-04-11
    • 1970-01-01
    • 1970-01-01
    • 2019-09-01
    • 1970-01-01
    • 2013-04-04
    • 1970-01-01
    • 2019-05-29
    相关资源
    最近更新 更多