PostgreSQL中的字符串字面量和转义字符

140

尝试将转义字符插入表格中会导致警告。

例如:

create table EscapeTest (text varchar(50));

insert into EscapeTest (text) values ('This is the first part \n And this is the second');

产生警告:

WARNING:  nonstandard use of escape in a string literal

(使用PSQL 8.2)

有人知道如何解决这个问题吗?

5个回答

157
部分正确。已插入文本,但仍会生成警告。
我发现一篇讨论表明需要在文本前加上'E',如下所示:
insert into EscapeTest (text) values (E'This is the first part \n And this is the second');

这样做消除了警告,但文本仍未正确返回。当我按照Michael的建议添加了额外的斜杠时,它起作用了。
因此:
insert into EscapeTest (text) values (E'This is the first part \\n And this is the second');

5
请注意,在PostgreSQL 9.0中,“E'testing\x20double-slash'”将被解释为“testing\x20double-slash”,因此只有单斜杠方法适用于使用E'string'样式文字的情况。 - Alexander
2
有关PostgreSQL 9.2,请参阅:http://www.postgresql.org/docs/9.2/interactive/sql-syntax-lexical.html#SQL-SYNTAX-STRINGS-ESCAPE - Pitt
注意:我发现当我在查询参数中使用E'\n'作为psql的\copy元命令时,它被写入文件时会被写成'\n'而不是换行符。 - Stew

53
酷。
我还找到了关于E的文档。

http://www.postgresql.org/docs/8.3/interactive/sql-syntax-lexical.html#SQL-SYNTAX-STRINGS

由'Randall'进行的引用格式化

PostgreSQL还接受“转义”字符串常量,这是SQL标准的扩展。转义字符串常量是通过在开头的单引号之前写入字母E(大写或小写)来指定的,例如E'foo'。(在跨行继续转义字符串常量时,只在第一个开头引号之前写入E。)在转义字符串中,反斜杠字符(\)开始一个类似C语言的反斜杠转义序列,其中反斜杠和后面的字符组合表示一个特殊的字节值:
\b是退格符,
\f是换页符,
\n是换行符,
\r是回车符,
\t是制表符。

还支持
\<digits>,其中<digits>表示一个八进制字节值,以及
\x<hexdigits>,其中<hexdigits>表示一个十六进制字节值。
(您有责任确保您创建的字节序列在服务器字符集编码中是有效的字符。)

反斜杠后面的任何其他字符都被视为字面量。因此,要包含一个反斜杠字符,请写两个反斜杠(\\)。此外,单引号可以通过写入\'来包含在转义字符串中,除了正常的''方式。

6

由于您在字符串中使用反斜杠,因此发出了警告。如果要避免此消息,请键入以下命令“set standard_conforming_strings=on;”。然后在包含要 PostgreSQL 解释的反斜杠的字符串前面使用“E”。


1
不完全是这样。如果我设置了standard_conforming_strings=on,并运行命令\copy xxxxxxxxxxx FROM /support01/db/data/xxxxxxxxx_7F.txt DELIMITER AS E'\x7f',我会得到parse error at "'\x7f'"的错误。如果我将standard_conforming_strings=off;并使用相同的命令,但没有E和引号...(DELIMITER AS \x7f),我会收到警告消息,但数据可以正常加载。 因此,在这种情况下,您的说法可能是正确的,但并非绝对。 - user329807
我之前提到的是 SQL 语句中的字符串,而你现在使用的是 psql 命令。如果你使用 COPY 命令而不是 \copy 命令,是否会出现相同的错误? - eppesuig
1
这是正确的答案。现代版本的PG默认打开它。 - jpmc26

3

我认为Postgres在输入时截断你的数据的可能性非常小 - 它要么拒绝它,要么按原样存储。

milen@dev:~$ psql
Welcome to psql 8.2.7, the PostgreSQL interactive terminal.

Type:  \copyright for distribution terms
       \h for help with SQL commands
       \? for help with psql commands
       \g or terminate with semicolon to execute query
       \q to quit

milen=> create table EscapeTest (text varchar(50));
CREATE TABLE
milen=> insert into EscapeTest (text) values ('This will be inserted \n This will not be');
WARNING:  nonstandard use of escape in a string literal
LINE 1: insert into EscapeTest (text) values ('This will be inserted...
                                              ^
HINT:  Use the escape string syntax for escapes, e.g., E'\r\n'.
INSERT 0 1
milen=> select * from EscapeTest;
          text
------------------------
 This will be inserted
  This will not be
(1 row)

milen=>

请尝试使用我提供的测试用例,您将亲眼看到它。 - rjohnston
有趣的是,看起来问题出在JDBC驱动程序上,因为从数据库中输出的文本明显被截断了... - rjohnston
3
在某些特定情况下,Postgres确实会在输入时截断数据。例如,一个 character varying(4) 列给出 "test "(单词后面有两个空格,共6个字符)的输入将截断空格并存储值 "test"。然而,通常情况下,您可以假设Postgres会产生错误而不是截断您的数据。 - Bryson

0

真的很愚蠢的问题:您确定字符串正在被截断,而不只是在您指定的换行符处被打断(并且可能不显示在您的界面中)吗?也就是说,您是否期望该字段显示为

This will be inserted \n This will not be

还是

This will be inserted

This will not be

此外,您使用的是什么界面?有可能在途中有些东西会吃掉您的反斜杠吗?


1
这种情况发生在我身上。文本被插入到文本框中,查看源代码,确实有引号并且整个文本都存在,只是不可见。 - roberthuttinger

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接