我试图在Postgres中使用FOR
循环来计算我的数据库中每个地理位置的(变量)范围内的数据平均值。我正在使用python / psycopg2。这是代码:
query ='''
DECLARE geoids RECORD;
BEGIN
RAISE NOTICE 'Beginning average calculation';
FOR geoids IN select*from census_blocks
WHERE ST_contains((select geom from census_cbsa
WHERE cbsafp10='%s'),census_blocks.geom)
LOOP
INSERT INTO temp_avgs VALUES
(geoids,
select avg(select alljobs from accessibility_results
WHERE geoid=geoids
AND deptime BETWEEN '%s' and '%s'
AND threshold='%s')
END LOOP;
END;
'''
我收到的错误是
psycopg2.ProgrammingError: syntax error at or near "RECORD"
LINE 2: DECLARE geoids RECORD;
如果我删除此DECLARE
语句(因为我认为LOOP
变量超过选择值会自动声明为RECORD
),则错误变为:
psycopg2.ProgrammingError: syntax error at or near "RAISE"
LINE 4: RAISE NOTICE 'Beginning average calculation';
我应该如何正确格式化此查询?
答案 0 :(得分:1)
您正在使用PL / pgSQL代码,但正试图将其短语为SQL查询。那是不可能的。
使用DO
语句或(因为您要使用参数)创建plpgsql function:
CREATE OR REPLACE FUNCTION foo(_cbsafp10 ?type? -- replace with ...
,_deptime_from timestamp? -- ... actual data types
,_deptime_to timestamp?
,_threshold ?type?)
RETURNS void AS
$func$
DECLARE
rec RECORD;
BEGIN
FOR rec IN
SELECT b.*
FROM census_blocks b
JOIN census_cbsa c ON ST_contains(c.geom, b.geom)
WHERE c.cbsafp10 = _cbsafp10
LOOP
INSERT INTO temp_avgs -- you might add a target list for safety. depends ..
SELECT rec.*, avg(alljobs)
FROM accessibility_results
WHERE geoid = rec.geoid -- assuming you join on column "geoid"?
AND deptime BETWEEN _deptime_from AND _deptime_to
AND threshold = _threshold;
END LOOP;
END
$func$ LANGUAGE plpgsql;
确保在您的客户端正确使用引号!
RAISE
是一个plpgsql命令,不是一个SQL命令。这是为了演示plpgsql函数的基础知识。但是,正如@Gordon已经提供的那样,只需使用单个INSERT
语句执行相同的。进一步解开:
INSERT INTO temp_avgs -- you might add a target list for safety. depends ..
SELECT b.*, avg(alljobs)
FROM census_cbsa c
JOIN census_blocks b ON ST_contains(c.geom, b.geom)
JOIN accessibility_results a ON a.geoid = b.geoid
WHERE c.cbsafp10 = %s
AND a.deptime BETWEEN %s AND %s
AND a.threshold = %s
GROUP BY b.geoid; -- assuming b.geoid is the primary key
答案 1 :(得分:0)
如何将它作为单个选择进行短语。像这样:
INSERT INTO temp_avgs(geoid, average)
select cb.geoid, avg(aj.alljobs)
from census_blocks cb join
accessibility_results ar
on cb.geoid = ar.geoid
WHERE ST_contains((select geom from census_cbsa WHERE cbsafp10='%s'), cb.geom) and
ar.deptime BETWEEN '%s' and '%s' AND ar.threshold='%s'
group by cb.geoid;
我不确定所有列的来源,因此表别名有点猜测。