【问题标题】:SQL state: 42601 syntax error at or near "11"SQL 状态:“11”处或附近出现 42601 语法错误
【发布时间】:2013-05-18 22:03:42
【问题描述】:

我有一个表address_all,它被几个地址表继承。 address_history 继承自父表 history_all 并保留当前地址信息。我正在创建继承address_all 表并将信息从address_history 复制到新表的新表。

我的存储过程如下所示。当我调用它时,我遇到了一些错误。为了更好地解释错误,我使用了行号。

1  CREATE OR REPLACE FUNCTION somefunc()
2  RETURNS void AS
3  $BODY$
4  DECLARE
5   year_id INTEGER;
6   month_id INTEGER;
7   week_id INTEGER;
8   addresstablename text; 
9   backupdays text;
10 BEGIN
11  week_id := EXTRACT(DAY FROM TIMESTAMP 'now()');
12  month_id := EXTRACT(MONTH FROM TIMESTAMP 'now()');
13  year_id := EXTRACT(YEAR FROM TIMESTAMP 'now()');
14  addresstablename := 'address_history_' || week_id || '_' || month_id || '_' || year_id;
15  backupdays:= date_trunc('hour',CURRENT_TIMESTAMP - interval '7 days');
16  EXECUTE 'create table ' || addresstablename || '() INHERITS (address_all)';
17  EXECUTE 'insert into ' || addresstablename || ' select * from address_history where address_timestamp >= ' || backupdays || ''; --AS timestamp without time zone);  
18 END;
19 $BODY$
20 LANGUAGE 'plpgsql' VOLATILE;

当我跑步时:

select somefunc()

我收到此错误:

ERROR:  syntax error at or near "12"
LINE 1: ...story where address_timestamp >= 2012-07-31 12:00:00-0...
                                                         ^
QUERY:  insert into address_history_7_8_2012 select * from address_history where address_timestamp >= 2012-07-31 12:00:00-04
CONTEXT:  PL/pgSQL function "somefunc" line 14 at EXECUTE statement

 ********** Error **********

ERROR: syntax error at or near "12"
SQL state: 42601
Context: PL/pgSQL function "somefunc" line 14 at EXECUTE statement

【问题讨论】:

    标签: postgresql datetime plpgsql dynamic-sql


    【解决方案1】:

    试试这个大大简化的形式:

    CREATE OR REPLACE FUNCTION somefunc()
      RETURNS void AS
    $func$
    DECLARE
     addresstablename text := 'address_history_' || to_char(now(), 'FMDD_MM_YYYY');
    
    BEGIN
     EXECUTE 
     'CREATE TABLE ' || addresstablename || '() INHERITS (address_all)';
    
     EXECUTE
     'INSERT INTO ' || addresstablename || '
      SELECT *
      FROM   address_history
      WHERE  address_timestamp >= $1'
     USING date_trunc('hour', now() - interval '7 days');
    
    END
    $func$ LANGUAGE plpgsql;
    

    要点:

    • 您可以在声明时在 plpgsql 中分配变量。简化代码。

    • 使用to_char() 格式化您的日期。简单得多。

    • now() 和 CURRENT_TIMESTAMP 做同样的事情。

    • 不要引用'now()',如果需要当前时间戳,请使用now()(不带引号)。

    • 使用USING clause with EXECUTE,因此您不必像您一样将timestamp 转换为text 并返回 - 可能会遇到引用问题。更快、更简单、更安全。

    • 在LANGUAGE plpgsql 中,plpgsql 是关键字,不应被引用。

    • 您可能希望使用CREATE TABLE IF NOT EXISTS 检查表是否已存在,自 PostgreSQL 9.1 起可用。

    【讨论】:

    • 感谢您为我的查询提供更多帮助。我是 postgres 的新手。
    【解决方案2】:

    显然您需要引用backupdays,否则它不会被视为解析时间戳的字符串。

    【讨论】:

      【解决方案3】:

      您正在使用字符串操作构建 SQL,因此您必须像使用任何其他语言一样正确引用所有内容。有一个few functions that you'll want to know about:

      • quote_ident:引用一个标识符,例如表名。
      • quote_literal:引用一个字符串以用作字符串文字。
      • quote_nullable:与 quote_literal 一样,但也能正确处理 NULL。

      这样的事情会更好地为您服务:

      EXECUTE 'create table ' || quote_ident(addresstablename) || ...
      EXECUTE 'insert into '  || quote_ident(addresstablename) || ... || quote_literal(backupdays) ...
      

      quote_ident 在您的情况下不是必需的,但这是一个好习惯。

      【讨论】:

      • quote_literal() 和 quote_ident() 通常是很好的建议。在这种情况下,你也不需要,我会声称。表名addresstablename是在函数内部生成的,不接受用户输入,所以可以直接使用。变量backupdays 可以与USING 子句一起应用,这样可以完全节省转换和引用。
      • 感谢分享 quote_ident、quote_literal 和 quote_nullable。我一定会在我的查询中使用这些。非常感谢。
      • @ErwinBrandstetter:因此,“quote_ident 电话在您的情况下不是必需的,但它们是一个好习惯。”我会声称 quote_ident 应该是你的手指做的默认操作,然后如果你确定你不需要它,请删除它。
      • @muistooshort:我不能不同意这一点。不要误会我的意思,我赞成你的回答 - 这是 lserni 简单评论的豪华版。
      • @ErwinBrandstetter:不用担心,我只是戴上“数据库专家”的帽子,并努力确保一切都定义明确且没有歧义 :)
      猜你喜欢
      • 2021-02-28
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-12-04
      • 2013-04-23
      • 1970-01-01
      • 2021-12-13
      相关资源
      最近更新 更多