Postgresql 8.4更新plpgsql函数查询语法错误
Postgresql 8.4 update query syntax error in plpgsql function
我正在使用 PostgreSQL 8.4 并创建一个 plpgsql 函数。在这个函数的主体中,我有一个更新记录的查询。
...
UPDATE device_syncfiles SET
state_code = 1, updated_at = NOW() at time zone 'UTC'
WHERE
((state_code = 2 AND EXTRACT(EPOCH FROM (NOW() at time zone 'UTC' - updated_at::timestamp without time zone)) > 3600) OR
(state_code = 3 AND EXTRACT(EPOCH FROM (NOW() at time zone 'UTC' - updated_at::timestamp without time zone)) > 3600));
...
当我将此函数加载到数据库中时,出现语法错误
ERROR: syntax error at or near ""
LINE 1: UPDATE device_syncfiles SET = 1, = NOW() at time z...
^
QUERY: UPDATE device_syncfiles SET = 1, = NOW() at time zone 'UTC' WHERE (( = 2 AND EXTRACT(EPOCH FROM (NOW() at time zone 'UTC' - ::timestamp without time zone)) > ) OR ( = 3 AND EXTRACT(EPOCH FROM (NOW() at time zone 'UTC' - ::timestamp without time zone)) > ))
CONTEXT: SQL statement in PL/PgSQL function "syncfile_get" near line 19
我找不到这个查询有任何问题。这里有什么问题?
更新:(缺少信息)
Table: device_syncfiles
id PK integer auto inc
user_id integer FK
file_name character varying(255) NOT NULL,
state_code integer NOT NULL FK,
md5 character varying(255) NOT NULL,
msg character varying(255),
created_at timestamp without time zone,
updated_at timestamp without time zone
函数:syncfile_get()
CREATE OR REPLACE FUNCTION syncfile_get()
RETURNS TABLE(id integer, user_id integer, file_name character varying, state_code integer, md5 character varying, created_at timestamp without time zone, updated_at timestamp without time zone) AS
$BODY$
DECLARE
_device_syncfile_id integer;
_download_timeout integer;
_processing_timeout integer;
BEGIN
-- GET all timeout info
SELECT state_timeout INTO _download_timeout FROM device_syncfile_states
WHERE state_name = 'downloading';
SELECT state_timeout INTO _processing_timeout FROM device_syncfile_states
WHERE state_name = 'processing';
-- GET syncfile id
_device_syncfile_id = NULL;
-- Reset timed out file to idel state
UPDATE device_syncfiles SET
state_code = 1, updated_at = NOW() at time zone 'UTC'
WHERE
((state_code = 2 AND EXTRACT(EPOCH FROM (NOW() at time zone 'UTC' - updated_at::timestamp without time zone)) > _download_timeout) OR
(state_code = 3 AND EXTRACT(EPOCH FROM (NOW() at time zone 'UTC' - updated_at::timestamp without time zone)) > _processing_timeout));
-- GET the id of one idel/timed out file => result could be a integer or NULL
SELECT device_syncfiles.id INTO _device_syncfile_id FROM device_syncfiles
WHERE
device_syncfiles.state_code = 1 OR
(device_syncfiles.state_code = 2 AND EXTRACT(EPOCH FROM (NOW() at time zone 'UTC' - device_syncfiles.updated_at::timestamp without time zone)) > _download_timeout) OR
(device_syncfiles.state_code = 3 AND EXTRACT(EPOCH FROM (NOW() at time zone 'UTC' - device_syncfiles.updated_at::timestamp without time zone)) > _processing_timeout)
LIMIT 1;
-- WHEN NULL skip state update and return empty set of record
-- Otherwise return the set of record with the id found in last step
IF _device_syncfile_id IS NOT NULL THEN
PERFORM syncfile_update(_device_syncfile_id, 2, NULL);
END IF;
RETURN QUERY SELECT
device_syncfiles.id,
device_syncfiles.user_id ,
device_syncfiles.file_name ,
device_syncfiles.state_code ,
device_syncfiles.md5 ,
device_syncfiles.created_at ,
device_syncfiles.updated_at
FROM device_syncfiles WHERE device_syncfiles.id = _device_syncfile_id;
END;
$BODY$
LANGUAGE plpgsql VOLATILE
很多个问题。
0.
I am using Postgresql 8.4
Postgres 8.4 于 2014 年 7 月停产。Consider upgrading to a current version. 紧急。
1.
你的问题没有透露完整的功能(至少是页眉和页脚),也没有任何 table 定义和一些示例数据来帮助我们帮助你。
我必须做出假设,我有根据的猜测是您有一个名为 state_code
的函数参数,它与相同的列名冲突。在三个处。基础知识:
- How to return result of a SELECT inside a function in PostgreSQL?
您必须知道 RETURNS TABLE
子句中声明的所有字段也是有效的 OUT
参数。 (如第一句第一句所述link。)所以你的Q更新证实了我的假设。
2.
您的错误消息在此处报告了 第一个 实例:
UPDATE device_syncfiles SET
<b>state_code</b> = 1 ...
这是 0. 的结果。您正被早已死去和遗忘的 Postgres 版本绊倒,在该版本中,函数创建时的表面语法检查用于检测 UPDATE
语句的目标列与函数参数之间的命名冲突。这很愚蠢,后来被删除了:那些目标列不能与主体上的函数参数冲突。
您的错误在 Postgres 8.4 中重现:dbfiddle here
在 Postgres 9.4 中不会发生同样的事情:dbfiddle here
要修复,最好重命名函数参数,避免冲突。相关:
3.
还有两个实例:
WHERE
((<b>state_code</b> = 2 AND EXTRACT(EPOCH FROM (NOW() at time zone 'UTC' - updated_at::timestamp without time zone)) > 3600) OR
(<b>state_code</b> = 3 AND EXTRACT(EPOCH FROM (NOW() at time zone 'UTC' - updated_at::timestamp without time zone)) > 3600));
任何版本都需要修复。 Postgres 无法判断是解析为函数参数还是 table 列。最好 table-限定所有列以避免与参数名称先验的任何可能的冲突。 (UPDATE
目标列除外,它们不需要也不允许 table 限定。)
4.
这仍然是猪口红。像这样改进查询:
UPDATE device_syncfiles d
SET state_code = 1
, updated_at = NOW() AT TIME ZONE 'UTC'
WHERE d.state_code IN (2, 3)
AND d.updated_at < (now() - interval '1 hour') AT TIME ZONE 'UTC';
更短,更快,可以在 updated_at
.
上使用索引
5.
最后考虑使用 timestamp with time zone
而不是 timestamp without time zone
开头:
- Ignoring timezones altogether in Rails and PostgreSQL
我正在使用 PostgreSQL 8.4 并创建一个 plpgsql 函数。在这个函数的主体中,我有一个更新记录的查询。
...
UPDATE device_syncfiles SET
state_code = 1, updated_at = NOW() at time zone 'UTC'
WHERE
((state_code = 2 AND EXTRACT(EPOCH FROM (NOW() at time zone 'UTC' - updated_at::timestamp without time zone)) > 3600) OR
(state_code = 3 AND EXTRACT(EPOCH FROM (NOW() at time zone 'UTC' - updated_at::timestamp without time zone)) > 3600));
...
当我将此函数加载到数据库中时,出现语法错误
ERROR: syntax error at or near ""
LINE 1: UPDATE device_syncfiles SET = 1, = NOW() at time z...
^
QUERY: UPDATE device_syncfiles SET = 1, = NOW() at time zone 'UTC' WHERE (( = 2 AND EXTRACT(EPOCH FROM (NOW() at time zone 'UTC' - ::timestamp without time zone)) > ) OR ( = 3 AND EXTRACT(EPOCH FROM (NOW() at time zone 'UTC' - ::timestamp without time zone)) > ))
CONTEXT: SQL statement in PL/PgSQL function "syncfile_get" near line 19
我找不到这个查询有任何问题。这里有什么问题?
更新:(缺少信息)
Table: device_syncfiles
id PK integer auto inc
user_id integer FK
file_name character varying(255) NOT NULL,
state_code integer NOT NULL FK,
md5 character varying(255) NOT NULL,
msg character varying(255),
created_at timestamp without time zone,
updated_at timestamp without time zone
函数:syncfile_get()
CREATE OR REPLACE FUNCTION syncfile_get()
RETURNS TABLE(id integer, user_id integer, file_name character varying, state_code integer, md5 character varying, created_at timestamp without time zone, updated_at timestamp without time zone) AS
$BODY$
DECLARE
_device_syncfile_id integer;
_download_timeout integer;
_processing_timeout integer;
BEGIN
-- GET all timeout info
SELECT state_timeout INTO _download_timeout FROM device_syncfile_states
WHERE state_name = 'downloading';
SELECT state_timeout INTO _processing_timeout FROM device_syncfile_states
WHERE state_name = 'processing';
-- GET syncfile id
_device_syncfile_id = NULL;
-- Reset timed out file to idel state
UPDATE device_syncfiles SET
state_code = 1, updated_at = NOW() at time zone 'UTC'
WHERE
((state_code = 2 AND EXTRACT(EPOCH FROM (NOW() at time zone 'UTC' - updated_at::timestamp without time zone)) > _download_timeout) OR
(state_code = 3 AND EXTRACT(EPOCH FROM (NOW() at time zone 'UTC' - updated_at::timestamp without time zone)) > _processing_timeout));
-- GET the id of one idel/timed out file => result could be a integer or NULL
SELECT device_syncfiles.id INTO _device_syncfile_id FROM device_syncfiles
WHERE
device_syncfiles.state_code = 1 OR
(device_syncfiles.state_code = 2 AND EXTRACT(EPOCH FROM (NOW() at time zone 'UTC' - device_syncfiles.updated_at::timestamp without time zone)) > _download_timeout) OR
(device_syncfiles.state_code = 3 AND EXTRACT(EPOCH FROM (NOW() at time zone 'UTC' - device_syncfiles.updated_at::timestamp without time zone)) > _processing_timeout)
LIMIT 1;
-- WHEN NULL skip state update and return empty set of record
-- Otherwise return the set of record with the id found in last step
IF _device_syncfile_id IS NOT NULL THEN
PERFORM syncfile_update(_device_syncfile_id, 2, NULL);
END IF;
RETURN QUERY SELECT
device_syncfiles.id,
device_syncfiles.user_id ,
device_syncfiles.file_name ,
device_syncfiles.state_code ,
device_syncfiles.md5 ,
device_syncfiles.created_at ,
device_syncfiles.updated_at
FROM device_syncfiles WHERE device_syncfiles.id = _device_syncfile_id;
END;
$BODY$
LANGUAGE plpgsql VOLATILE
很多个问题。
0.
I am using Postgresql 8.4
Postgres 8.4 于 2014 年 7 月停产。Consider upgrading to a current version. 紧急。
1.
你的问题没有透露完整的功能(至少是页眉和页脚),也没有任何 table 定义和一些示例数据来帮助我们帮助你。
我必须做出假设,我有根据的猜测是您有一个名为 state_code
的函数参数,它与相同的列名冲突。在三个处。基础知识:
- How to return result of a SELECT inside a function in PostgreSQL?
您必须知道 RETURNS TABLE
子句中声明的所有字段也是有效的 OUT
参数。 (如第一句第一句所述link。)所以你的Q更新证实了我的假设。
2.
您的错误消息在此处报告了 第一个 实例:
UPDATE device_syncfiles SET
<b>state_code</b> = 1 ...
这是 0. 的结果。您正被早已死去和遗忘的 Postgres 版本绊倒,在该版本中,函数创建时的表面语法检查用于检测 UPDATE
语句的目标列与函数参数之间的命名冲突。这很愚蠢,后来被删除了:那些目标列不能与主体上的函数参数冲突。
您的错误在 Postgres 8.4 中重现:dbfiddle here
在 Postgres 9.4 中不会发生同样的事情:dbfiddle here
要修复,最好重命名函数参数,避免冲突。相关:
3.
还有两个实例:
WHERE
((<b>state_code</b> = 2 AND EXTRACT(EPOCH FROM (NOW() at time zone 'UTC' - updated_at::timestamp without time zone)) > 3600) OR
(<b>state_code</b> = 3 AND EXTRACT(EPOCH FROM (NOW() at time zone 'UTC' - updated_at::timestamp without time zone)) > 3600));
任何版本都需要修复。 Postgres 无法判断是解析为函数参数还是 table 列。最好 table-限定所有列以避免与参数名称先验的任何可能的冲突。 (UPDATE
目标列除外,它们不需要也不允许 table 限定。)
4.
这仍然是猪口红。像这样改进查询:
UPDATE device_syncfiles d
SET state_code = 1
, updated_at = NOW() AT TIME ZONE 'UTC'
WHERE d.state_code IN (2, 3)
AND d.updated_at < (now() - interval '1 hour') AT TIME ZONE 'UTC';
更短,更快,可以在 updated_at
.
5.
最后考虑使用 timestamp with time zone
而不是 timestamp without time zone
开头:
- Ignoring timezones altogether in Rails and PostgreSQL