如何在动态 sql 查询中使用 WITH 块
How to use a WITH block with dynamic sql query
我有一个 plpgsql
函数需要根据用户输入从 3 table 秒开始准备数据,并使用 COPY TO
导出数据。数据是道路交通事故,所以3个table分别是accident
、casualty
和vehicle
,每个事故链接到车辆和伤亡中的零个或多个记录tables 通过存在于所有三个 tables 中的 accidentid
列。 severity
和local_authorities
是输入参数(都是text []
)。
sql_query = 'SELECT COUNT(*) FROM accident WHERE severity = ANY(' || quote_literal(severity)
|| ') AND local_auth = ANY (' || quote_literal(local_authorities) || ')';
EXECUTE sql_query INTO result_count;
IF result_count > 0 THEN
-- replace Select Count(*) With Select *
sql_query = Overlay(sql_query placing '*' from 8 for 8);
-- copy the accident data first
EXECUTE 'COPY (' || sql_query || ') TO ' || quote_literal(file_path || file_name_a) ||
' CSV';
这第一位会得到相关的事故,所以我现在正在寻找最有效的方法来使用第一个查询中的 accidentid 来下载相关的车辆和伤亡数据。
我想我可以像这样使用 WITH
块:
-- replace * with accidentid
sql_query = Overlay(sql_query placing 'accidentid' from 8 for 1);
WITH acc_ids AS (sql_query)
EXECUTE 'COPY (SELECT * FROM vehicle WHERE accidentid IN (SELECT accidentid FROM
acc_ids)) TO ' || out_path_and_vfilename || ' CSV';
EXECUTE 'COPY (SELECT * FROM casualty WHERE accidentid IN (SELECT accidentid FROM
acc_ids)) TO ' || out_path_and_cfilename || ' CSV';
但出现错误:
ERROR: syntax error at or near ""
LINE 1: WITH acc_ids AS ( ) EXECUTE 'COPY (SELECT * FROM accident....
我已经在非动态测试用例中尝试了上述方法,例如
WITH acc_ids AS (
SELECT accidentid FROM accident
WHERE severity = ANY ('{3,2}')
AND local_auth = ANY ('{E09000001,E09000002}')
)
SELECT * FROM vehicle
WHERE accidentid IN (
SELECT accidentid FROM acc_ids);
有效。不幸的是服务器仍然运行宁Postgres 8.4
所以我暂时不能使用format()
。
也许 WITH
块不可能做到这一点,但我希望它至少说明了我正在努力实现的目标。
Edit/Update
主要目标是从 3 个 table 的 3 个单独的 csv
文件中获取相关数据,理想情况下无需 运行 在 [=16= 上进行选择] table 3次
如果你想运行一个存储在字符串变量中的查询(部分),你需要一个像
这样的动态查询
EXECUTE 'WITH acc_ids AS (' || sql_query || ')'
'SELECT ... ';
要么整个查询是由 EXECUTE
执行的字符串,要么整个查询是静态的 SQL。不能混用。
您需要 CTE 吗?如果您可以将查询表示为连接,优化器将有更多选择。
这就是我在没有 CTE 的情况下需要做的事情,但我看不出这是解决这个问题的最有效方法,因为我必须在 accident
table 3 上执行相同的查询次数:
sql_query = sql_query || which_tab || ' WHERE severity = ANY ('||
quote_literal(severity) ||') AND ' || date_start || ' AND ' ||
date_end || ' AND local_auth = ANY (' ||
quote_literal(local_authorities) || ')';
-- replace * with COUNT(*)
sql_query = Overlay(sql_query placing 'COUNT(*)' from 8 for 1);
EXECUTE sql_query INTO result_count;
IF result_count > 0 THEN
-- replace COUNT(*) with *
sql_query = Overlay(sql_query placing '*' from 8 for 8);
-- copy the accident data first
EXECUTE 'COPY (' || sql_query || ') TO ' || quote_literal(file_path ||
file_name_a) || ' CSV';
sql_query = Overlay(sql_query placing 'accidentid' from 8 for 1);
-- vehicles
EXECUTE 'COPY (SELECT * FROM vehicle WHERE accidentid IN (
SELECT accidentid FROM accident
WHERE severity = ANY (' || quote_literal(severity) || ')
AND local_auth = ANY (' || quote_literal(local_authorities) ||')))
TO ' || quote_literal(file_path || file_name_v) || ' CSV';
-- casualties
EXECUTE 'COPY (SELECT * FROM casualty WHERE accidentid IN (
SELECT accidentid FROM accident
WHERE severity = ANY (' || quote_literal(severity) || ')
AND local_auth = ANY (' || quote_literal(local_authorities) ||')))
TO ' || quote_literal(file_path || file_name_c) || ' CSV';
END IF;
我有一个 plpgsql
函数需要根据用户输入从 3 table 秒开始准备数据,并使用 COPY TO
导出数据。数据是道路交通事故,所以3个table分别是accident
、casualty
和vehicle
,每个事故链接到车辆和伤亡中的零个或多个记录tables 通过存在于所有三个 tables 中的 accidentid
列。 severity
和local_authorities
是输入参数(都是text []
)。
sql_query = 'SELECT COUNT(*) FROM accident WHERE severity = ANY(' || quote_literal(severity)
|| ') AND local_auth = ANY (' || quote_literal(local_authorities) || ')';
EXECUTE sql_query INTO result_count;
IF result_count > 0 THEN
-- replace Select Count(*) With Select *
sql_query = Overlay(sql_query placing '*' from 8 for 8);
-- copy the accident data first
EXECUTE 'COPY (' || sql_query || ') TO ' || quote_literal(file_path || file_name_a) ||
' CSV';
这第一位会得到相关的事故,所以我现在正在寻找最有效的方法来使用第一个查询中的 accidentid 来下载相关的车辆和伤亡数据。
我想我可以像这样使用 WITH
块:
-- replace * with accidentid
sql_query = Overlay(sql_query placing 'accidentid' from 8 for 1);
WITH acc_ids AS (sql_query)
EXECUTE 'COPY (SELECT * FROM vehicle WHERE accidentid IN (SELECT accidentid FROM
acc_ids)) TO ' || out_path_and_vfilename || ' CSV';
EXECUTE 'COPY (SELECT * FROM casualty WHERE accidentid IN (SELECT accidentid FROM
acc_ids)) TO ' || out_path_and_cfilename || ' CSV';
但出现错误:
ERROR: syntax error at or near ""
LINE 1: WITH acc_ids AS ( ) EXECUTE 'COPY (SELECT * FROM accident....
我已经在非动态测试用例中尝试了上述方法,例如
WITH acc_ids AS (
SELECT accidentid FROM accident
WHERE severity = ANY ('{3,2}')
AND local_auth = ANY ('{E09000001,E09000002}')
)
SELECT * FROM vehicle
WHERE accidentid IN (
SELECT accidentid FROM acc_ids);
有效。不幸的是服务器仍然运行宁Postgres 8.4
所以我暂时不能使用format()
。
也许 WITH
块不可能做到这一点,但我希望它至少说明了我正在努力实现的目标。
Edit/Update
主要目标是从 3 个 table 的 3 个单独的 csv
文件中获取相关数据,理想情况下无需 运行 在 [=16= 上进行选择] table 3次
如果你想运行一个存储在字符串变量中的查询(部分),你需要一个像
这样的动态查询EXECUTE 'WITH acc_ids AS (' || sql_query || ')'
'SELECT ... ';
要么整个查询是由 EXECUTE
执行的字符串,要么整个查询是静态的 SQL。不能混用。
您需要 CTE 吗?如果您可以将查询表示为连接,优化器将有更多选择。
这就是我在没有 CTE 的情况下需要做的事情,但我看不出这是解决这个问题的最有效方法,因为我必须在 accident
table 3 上执行相同的查询次数:
sql_query = sql_query || which_tab || ' WHERE severity = ANY ('||
quote_literal(severity) ||') AND ' || date_start || ' AND ' ||
date_end || ' AND local_auth = ANY (' ||
quote_literal(local_authorities) || ')';
-- replace * with COUNT(*)
sql_query = Overlay(sql_query placing 'COUNT(*)' from 8 for 1);
EXECUTE sql_query INTO result_count;
IF result_count > 0 THEN
-- replace COUNT(*) with *
sql_query = Overlay(sql_query placing '*' from 8 for 8);
-- copy the accident data first
EXECUTE 'COPY (' || sql_query || ') TO ' || quote_literal(file_path ||
file_name_a) || ' CSV';
sql_query = Overlay(sql_query placing 'accidentid' from 8 for 1);
-- vehicles
EXECUTE 'COPY (SELECT * FROM vehicle WHERE accidentid IN (
SELECT accidentid FROM accident
WHERE severity = ANY (' || quote_literal(severity) || ')
AND local_auth = ANY (' || quote_literal(local_authorities) ||')))
TO ' || quote_literal(file_path || file_name_v) || ' CSV';
-- casualties
EXECUTE 'COPY (SELECT * FROM casualty WHERE accidentid IN (
SELECT accidentid FROM accident
WHERE severity = ANY (' || quote_literal(severity) || ')
AND local_auth = ANY (' || quote_literal(local_authorities) ||')))
TO ' || quote_literal(file_path || file_name_c) || ' CSV';
END IF;