☰
PostgreSQL 字符串中的单引号转义:`‘‘` 双写、`E` 前缀与美元引用详解
2026/10/8 7:00:57 网站建设 项目流程
  • 文档
  • 教程
  • 知识库

【免费下载链接】til

:memo: Today I Learned

项目地址:https://gitcode.com/gh_mirrors/ti/til
点击查看免费下载

在 PostgreSQL 中,varchar和text等字符串字面量一律使用单引号(')包裹,这就带来了一个绕不开的问题:当字符串内容本身包含单引号时,该如何书写?本指南以 postgres/escaping-a-quote-in-a-string.md 为核心,完整讲解最基础的单引号转义规则,并结合本仓库中同主题的 TIL 笔记,扩展出E前缀转义、美元引用(dollar quoting)与带标签美元引用三种替代方案。读完本文,你将能在 psql 交互环境与程序化生成的 SQL 中从容处理任何包含单引号、甚至包含$$序列的字符串字面量。

为什么单引号必须被转义

字符串字面量的定界符就是单引号本身。PostgreSQL 在解析select 'what''s up!';时,需要区分"作为定界符的单引号"和"作为内容的单引号"。如果不做任何处理直接写出'what's up!',解析器会把'what'当作完整字符串,随后s up!变成游离文本,最终因找不到配对的定界符而报语法错误。

PostgreSQL 官方给出的转义规则非常朴素:字符串字面量内部的单引号,用另一个单引号来转义。也就是说,把'写成'',两个连续的单引号中,第一个让第二个"脱去定界符身份",从而作为字符内容出现在最终字符串中。

方法一:双单引号转义(核心写法)

这是原文档给出的、也是 PostgreSQL 语义最标准、与standard_conforming_strings行为无关的写法。在 psql 中直接验证:

> select 'what''s up!'; ?column? ------------ what's up!

解析过程可以这样理解:字面量以第一个'开始,随后遇到两个连续单引号'',它们被整体解释为一个内容字符',最后一个'负责收尾。本仓库的姊妹笔记 postgres/two-ways-to-escape-a-quote-in-a-string.md 用who's on first?展示了同一个要点:

> select 'who''s on first?'; ?column? ----------------- who's on first? (1 row)

双单引号写法的最大优点是无条件可用:无论会话级配置standard_conforming_strings如何设置,它都按固定规则解析,不依赖任何上下文开关。缺点同样明显——当字符串中单引号密集出现时,肉眼很难数清引号配对的层级,例如同时包含it's、John's的文本会写成一长串'',阅读与维护成本较高。

常见的失败形态:未转义时的表现

把单引号直接塞进字符串而不做任何处理,查询不会报出"明确的错误",而是表现为语句迟迟不结束。原因在于 psql 认为字符串还没有闭合,会持续等待你输入闭合引号:

> select 'who's on first?'; ...

正如 postgres/two-ways-to-escape-a-quote-in-a-string.md 所描述的,这条查询不会执行,因为它"正在等待你关闭第二组引号"。遇到这种悬挂在续行状态的输入,可以按Ctrl-C中断,再补上转义后重新提交。

方法二:E前缀 + 反斜杠转义

除了双写单引号,postgres/two-ways-to-escape-a-quote-in-a-string.md 还记录了第二种思路:给字符串字面量加上E前缀,使反斜杠转义序列(escape sequence)在字符串内生效:

> select E'who\'s on first?'; ?column? ----------------- who's on first? (1 row)

这里E'...'让 PostgreSQL 以"转义字符串"的语义解析字面量,于是\'被解释为单个单引号字符。需要注意:在现代 PostgreSQL 中,standard_conforming_strings默认开启,普通字符串(不带E前缀)中的反斜杠会被当作普通字符处理,此时'who\'s on first?'不会得到你想要的结果;只有显式添加E前缀后反斜杠才具备转义能力。因此E前缀写法适合你确实想用反斜杠体系管理特殊字符的场景,日常写包含单引号的普通文本时,双单引号更直接。

方法三:美元引用(Dollar Quoting)

双单引号"易出错、且在程序化生成 SQL 时不好用",这是本仓库另一篇笔记 postgres/escaping-string-literals-with-dollar-quoting.md 提出的核心痛点。它的解决方案是用$$取代'作为定界符:

> select $$Isn't this even nicer?$$; ?column? ------------------------ Isn't this even nicer?

用法就是"把两端的'换成$$",字符串内部的单引号不再需要任何转义。这对两类场景尤其有价值:

  • 动态拼接 SQL:在应用代码里用字符串模板拼 SQL 时,双单引号要求拼装逻辑额外感知内容中的引号;美元引用让内容原样穿过拼接层。
  • 定义函数/存储过程体:函数体内部几乎必然出现字符串与引号,用$$...$$包裹 PL/pgSQL 函数体是 PostgreSQL 社区最常见的写法。

进阶:带标签的美元引用

如果字符串内容里碰巧出现了连续两个$符号(比如价格文本"$$$"),裸$$定界符也会冲突。此时可用带标签的美元引用。仓库笔记 postgres/label-dollar-quoted-strings-with-a-tag.md 给出了非常直观的 JSON 示例:

> select $JSON${"name": "Sally's Bistro", "price": "$$$"}$JSON$::jsonb; jsonb -------------------------------------------- {"name": "Sally's Bistro", "price": "$$$"} (1 row) > select $JSON${"name": "Sally's Bistro", "price": "$$$"}$JSON$->'name' as name; name ------------------ "Sally's Bistro" (1 row)

这段笔记的要点有三个:

  1. 标签放在两对$之间:本例标签为JSON,写作$JSON$ ... $JSON$,既能避开内容中的$$,又能向读者传达"这段字面量代表 JSON"的语义信息;
  2. 标签命名规则:标签遵循与未加引号标识符相同的规则,唯一例外是不能包含美元符号;
  3. 标签区分大小写:$JSON$与$json$是不同的定界符,书写时需保持一致。

借助带标签美元引用,第一段 SQL 把整段 JSON 文本(内含单引号Sally's与双美元$$$)直接转型为jsonb而无需思考任何字符需要转义;第二段则进一步证明,转型后的值可以像普通jsonb实体一样使用->运算符访问字段。

四种方案如何选择

方案写法示例适用场景注意点
双单引号'what''s up!'手写少量含单引号的文本引号密集时可读性差
E前缀E'who\'s on first?'需要反斜杠转义体系依赖E前缀显式开启转义语义
裸美元引用$$Isn't this nicer?$$程序化生成 SQL、函数体内容含$$时会冲突
带标签美元引用$JSON${...}$JSON$内容含$$或想表达语义标签不能含$,且区分大小写

仓库延伸阅读

围绕"字符串与引号"这一主题,本仓库的 postgres 目录下还有以下可直接对照的 TIL 笔记:

  • postgres/escaping-a-quote-in-a-string.md:本文核心——双单引号转义;
  • postgres/two-ways-to-escape-a-quote-in-a-string.md:''与E前缀两种方式对照;
  • postgres/escaping-string-literals-with-dollar-quoting.md:$$美元引用入门;
  • postgres/label-dollar-quoted-strings-with-a-tag.md:带标签美元引用处理含$$的内容。
  • 文档
  • 教程
  • 知识库

【免费下载链接】til

:memo: Today I Learned

项目地址:https://gitcode.com/gh_mirrors/ti/til
点击查看免费下载

相关推荐

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询