sm9*_*901 5 postgresql plpgsql
我正在尝试执行使用 plpgsql 在循环中重复调用的查询 - 循环遍历另一个表(命名坐标),其中包含网格的左上角和右下角纬度/经度坐标,我传递左上角和右下角纬度/ 经度值输入我的 CTE,以便显示在给定两个时间戳的这些坐标内发出的请求量(每小时)-。但是,我无法显示 CTE 的结果,并且收到以下错误消息:
ERROR: query has no destination for result data
HINT: If you want to discard the results of a SELECT, use PERFORM instead.
CONTEXT: PL/pgSQL function "inline_code_block" line 6 at SQL statement
Run Code Online (Sandbox Code Playgroud)
为了使整个查询根据需要工作,我应该在这里更改什么?我的代码如下:
DO $$
<<outer_scope>> DECLARE
coords RECORD;
BEGIN
FOR coords IN SELECT topleftlat, topleftlon, bottomrightlat, bottomrightlon FROM coordinates LOOP
WITH cal AS (
SELECT generate_series('2011-02-02 00:00:00'::timestamp ,
'2012-04-01 05:00:00'::timestamp ,
'1 hour'::interval) AS stamp
),
qqq AS (
SELECT date_trunc('hour', calltime) AS stamp, count(*) AS zcount
FROM mytable
WHERE calltime >= '2011-02-13 11:55:11'
AND calltime <= '2012-02-13 01:02:21'
AND (calltime::time >= '11:55:11'
OR calltime::time <= '01:02:21')
AND lat BETWEEN coords.bottomrightlat AND coords.topleftlat
AND lon BETWEEN coords.topleftlon AND coords.bottomrightlon
GROUP BY date_trunc('hour', calltime)
)
SELECT cal.stamp, COALESCE (qqq.zcount, 0) AS zcount
FROM cal
LEFT JOIN qqq ON cal.stamp = qqq.stamp
WHERE cal.stamp >= '2011-02-13 11:00:00'
AND cal.stamp <= '2012-02-13 01:02:21'
AND (
extract ('hour' from cal.stamp) >= extract ('hour' from '2011-02-13 11:00:00'::timestamp) or
extract ('hour' from cal.stamp) <= extract ('hour' from '2012-02-13 01:02:21'::timestamp)
)
ORDER BY stamp ASC;
END LOOP;
END;
$$;
Run Code Online (Sandbox Code Playgroud)
该DO
命令无法实际返回数据(除了使用RAISE
,或者您可以写入(临时)表 .. )。
您需要创建一个可以定义返回类型RETURNS
并调用它的 PL/pgSQL 函数。
你可以用 返回结果RETURN QUERY EXECUTE
。但我怀疑整个操作可以简化......
您可能根本不需要 plpgsql 或循环。考虑这个简单的 SQL 查询:
WITH v AS (
SELECT '2011-02-13 11:55:11'::timestamp AS _from -- provide times once
,'2012-02-13 01:02:21'::timestamp AS _to
)
, q AS (
SELECT c.coordinates_id
, date_trunc('hour', t.calltime) AS stamp
, count(*) AS zcount
FROM v
JOIN mytable t ON t.calltime BETWEEN v._from AND v._to
AND (t.calltime::time >= v._from::time OR
t.calltime::time <= v._to::time)
JOIN coordinates c ON (t.lat, t.lon)
BETWEEN (c.bottomrightlat, c.topleftlon)
AND (c.topleftlat, c.bottomrightlon)
GROUP BY c.coordinates_id, date_trunc('hour', t.calltime)
)
, cal AS (
SELECT generate_series(GREATEST('2011-02-02 00:00:00'::timestamp, v._from)
, LEAST('2012-04-01 05:00:00'::timestamp, v._to)
, '1 hour'::interval) AS stamp
FROM v
)
SELECT q.coordinates_id, cal.stamp, COALESCE (q.zcount, 0) AS zcount
FROM v, cal
LEFT JOIN q USING (stamp)
WHERE (cal.stamp::time >= v._from::time OR
cal.stamp::time <= v._to::time)
ORDER BY q.coordinates_id, stamp;
Run Code Online (Sandbox Code Playgroud)
不要循环遍历 table 中的行,而是coordinates
加入 CTE 并一次性生成整个结果。
当您聚合每一行时,coordinates
我们需要这个表的主键(或任何其他唯一的列集),我假设一个名为coordinates_id
.
我加入了CTE v
(即“值”)之上,以提供_from
与_to
仅一次时间戳。
我立即使用_from
和_to
来限制日历的时间范围,而不是WHERE
在最终的SELECT
.
GREATEST('2011-02-02 00:00:00'::timestamp, v._from)
LEAST('2012-04-01 05:00:00'::timestamp, v._to)
Run Code Online (Sandbox Code Playgroud)对于更简单的条件,我使用@kgrittn 在此相关答案中演示的“临时行” JOIN
:
ON (t.lat, t.lon)
BETWEEN (c.bottomrightlat, c.topleftlon)
AND (c.topleftlat, c.bottomrightlon)
Run Code Online (Sandbox Code Playgroud)::time
) 而不是使用extract ('hour' ..)
,因为它更简单、更快。我不是 100% 确定这正是您所追求的,但它应该非常接近。
归档时间: |
|
查看次数: |
5432 次 |
最近记录: |