- 文档
- 教程
- 知识库
【免费下载链接】til
:memo: Today I Learned
@>是 PostgreSQL 中最常见的包含(containment)运算符之一,常用于数组与 JSONB 的包含判断。但当你想知道这个运算符还能用于哪些数据类型、以及每种类型组合的返回结果时,手写 SQL 去翻系统目录相当繁琐。本文介绍 psql 元命令\do的用法:一条命令即可列出某个运算符在pg_catalog中的全部重载签名,并通过对数组、range、JSONB 等实际场景的解析,让你彻底掌握运算符重载与类型解析的思路。
\do元命令:查看运算符的全部签名
psql 提供了一系列以反斜杠开头的元命令(meta-command),其中\do专门用于查询系统中的运算符。它的基本用法是:
\do @>执行后 psql 会从系统目录中找出所有名为@>的运算符,并输出一张结果表:
List of operators Schema | Name | Left arg type | Right arg type | Result type | Description ------------+------+---------------+----------------+-------------+------------- pg_catalog | @> | aclitem[] | aclitem | boolean | contains pg_catalog | @> | anyarray | anyarray | boolean | contains pg_catalog | @> | anyrange | anyelement | boolean | contains pg_catalog | @> | anyrange | anyrange | boolean | contains pg_catalog | @> | box | box | boolean | contains pg_catalog | @> | box | point | boolean | contains pg_catalog | @> | circle | circle | boolean | contains pg_catalog | @> | circle | point | boolean | contains pg_catalog | @> | jsonb | jsonb | boolean | contains pg_catalog | @> | path | point | boolean | contains pg_catalog | @> | polygon | point | boolean | contains pg_catalog | @> | polygon | polygon | boolean | contains pg_catalog | @> | tsquery | tsquery | boolean | contains这张表的关键在Left arg type(左操作数类型)与Right arg type(右操作数类型)两列:它们决定了每一种运算符重载可以接受什么样的操作数组合。值得注意的是,所有重载的Result type都是boolean,这说明包含运算符本质上是返回真/假的谓词(predicate)。
\do的适用面不限于@>,它支持任意运算符。比如想知道<>(不等)有多少种重载,直接执行\do <>即可;想查看全表运算符,可以不带参数执行\do,psql 会列出当前可见的所有运算符。这也是排查“为什么这个运算符不适用于我的数据类型”最直接的手段:如果表中查不到你想要的操作数组合,说明该运算符对这对类型没有定义。
理解@>包含运算符的语义
@>表示“包含”(contains),判断左操作数是否包含右操作数。在仓库笔记 set-inclusion-with-hstore.md 中可以看到它的孪生运算符<@(“被包含于”)的用法:@>检查右操作数是否为左操作数的子集,<@则检查左操作数是否为右操作数的子集。
> select '"one"=>"1", "two"=>"2", "three"=>"3"'::hstore @> '"two"=>"2"'::hstore; ?column? ---------- t > select '"one"=>"1", "two"=>"2", "three"=>"3"'::hstore <@ '"two"=>"2"'::hstore; ?column? ---------- f理解了这个语义,再看上面\do @>的输出就会豁然开朗:表里列出的每一种操作数组合,都是“判断左操作数是否包含右操作数”这一语义在不同数据类型上的具体实现。
逐类解读:@>的多种重载签名
anyarray 与 anyarray
anyarray @> anyarray是数组包含判断。PostgreSQL 用anyarray作为伪类型(pseudo-type)来表示“任意数组类型”,因此这一个签名就覆盖了int[]、text[]等所有具体数组类型。配合仓库笔记 defining-arrays.md 中定义的数组,可以这样验证:
> select array['a','b','c'] @> array['a','c']; ?column? ---------- t即左数组是否包含右数组的全部元素(不要求顺序一致)。
anyrange 与 anyelement / anyrange
anyrange @> anyelement判断一个 range 区间是否包含某个元素,anyrange @> anyrange判断一个区间是否完全包含另一个区间。这是范围类型(range type)专属的重载,比如int4range、daterange等都可以直接使用。
jsonb 与 jsonb
jsonb @> jsonb是 JSON 路径包含判断:左 JSON 中是否包含右 JSON 的整个结构。它是日常业务查询中使用最频繁的重载之一,例如存储 JSON 的列里筛选“包含某个嵌套结构”的记录。仓库笔记 extracting-nested-json-data.md 展示了如何用json_extract_path取出嵌套值,而@>则是从相反方向——判断结构包含——来处理 JSONB 数据。
几何类型重载
box、circle、polygon、path、point几组重载服务于几何数据的空间包含判断:
box @> box、circle @> circle、polygon @> polygon:图形是否包含另一个图形;box @> point、circle @> point、path @> point、polygon @> point:图形是否包含某个点。
其他类型
aclitem[] @> aclitem:判断权限项数组是否包含某个权限项,用于 ACL(访问控制列表)判断;tsquery @> tsquery:判断一个全文检索查询是否包含另一个查询,服务于全文搜索场景。
\do背后的系统目录原理
\do之所以能瞬间给出答案,是因为 PostgreSQL 把所有运算符的元数据都存放在系统目录表中。从仓库笔记 types-by-category.md 可以看出,PostgreSQL 的类型信息存放在pg_type系统目录中,而运算符的信息则对应存放在pg_operator目录中——\do本质上是 psql 对pg_operator的封装查询。\do @>与如下形式的 SQL 等价:
select oprname, oprleft, oprright, oprresult from pg_operator where oprname = '@>';这就是为什么\do输出的每一行都对应一条独立的运算符重载定义:每个重载在pg_operator中都有一条记录,记录着它的左右操作数类型与返回类型。anyarray、anyrange、anyelement这些伪类型意味着该运算符是泛型(polymorphic)的,可以适配任意符合条件的具体类型。
使用场景与注意事项
- 排查类型不匹配:当一条查询报出 “operator does not exist: ... @> ...” 错误时,用
\do @>对照检查是否存在你想要的操作数组合,往往能立刻定位问题。 - 研究陌生运算符:遇到不熟悉的运算符,先
\do <运算符名>看它支持哪些类型,再结合语义猜测用途,是理解 PostgreSQL 运算符体系的捷径。 - 注意模式匹配:
\do的参数支持LIKE风格的通配符(如\do @*可匹配所有以@开头的运算符),便于批量浏览。 - schema 限定:输出的
Schema列为pg_catalog,说明这些是系统内置运算符;自定义运算符会显示在创建它的 schema 下,\do同样可以查到。
小结
\do是 psql 中最实用的元命令之一:它把隐藏在pg_operator系统目录中的运算符重载信息以表格形式呈现,让你一眼看清某个运算符的全部签名组合。以@>为例,通过\do @>可以看到它覆盖数组、range、jsonb、几何类型、tsquery 与 ACL 数组等十余种组合,每一种都对应着“包含”语义在不同数据类型上的实现。掌握这个命令,无论是排查类型错误、研究新运算符,还是理解 PostgreSQL 的类型体系,都会更加得心应手。
- 文档
- 教程
- 知识库
【免费下载链接】til
:memo: Today I Learned
相关推荐
PostgreSQL psql 实战:用 \g 元命令把查询结果写入文件
PostgreSQL psql 实战:用 \g 元命令把查询结果写入文件 在 psql 交互式会话中,绝大多数查询语句都以分号 ; 结尾来提交执行。其实 psq
文档教程知识库macOS版本查询革命:3分钟搞定所有版本信息
macOS版本查询革命:3分钟搞定所有版本信息 还在为查找macOS历史版本信息而头痛?面对众多版本号、构建号和发布时间,你是否感到无从下手?gibMacOS项
开发工具Steampipe跨版本兼容性:确保查询脚本在所有版本运行
Steampipe跨版本兼容性:确保查询脚本在所有版本运行 痛点直击:你的查询脚本为何突然失效? 还在为Steampipe升级后查询脚本报错而头疼?从v0.20
开发工具云原生
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考