PostgreSQL 表名模糊查询:pg_catalog、information_schema 与 LIKE 实战
发布时间:2026/10/14 4:40:00 锦皓数字建站

做数据库运维这些年最常被问到的一个问题就是“我有一堆表怎么找出名字里带某个关键字的”尤其是系统经过多年迭代表名命名不规范的时候这种需求几乎每周都会出现。最近我习惯把这类需求直接丢给 Qwen3.5-Plus让它先给一版 PostgreSQL 查询方案再结合自己的经验调整。今天就把这套“AI 辅助 系统表/信息模式 LIKE 模糊匹配”的组合打法完整拆给你包括具体的 SQL 写法、背后的原理、动态 SQL 扩展以及我实际踩过的一些坑。这套方法适合谁如果你是 PostgreSQL 的运维、后端开发或者正在做数据迁移、表结构梳理那这篇文章能帮你节省大量手动翻系统表的时间。哪怕你只是刚接触数据库只要跟着文章里的 SQL 跑一遍也能明白到底怎么通过 pg_catalog 和 information_schema 精准定位目标表。1. 问题场景与解决思路1.1 为什么需要按表名模糊查询先还原一下典型场景某天你接手一个老项目库里有几百张表命名风格五花八门。你想知道所有以tablename为前缀、或者中间包含tablename这个关键字的表有哪些。用客户端一个个点开树形目录找效率低且容易漏用\dt命令直接列全部表信息量太大。更合理的做法是写一条 SQL去查询数据库的元数据让数据库替我们完成过滤。在 PostgreSQL 里表名、列名、数据类型这些元数据存储在系统目录System Catalog和信息系统Information Schema中。系统目录是一组底层的表名字通常以pg_开头信息模式则是一套遵循 SQL 标准的视图让你用更统一的方式读取元数据。两者都能实现对表名的模糊匹配但存在一些细微差别。理解这些差别才能在不同场景下选出最合适的方案。1.2 两种系统目录pg_catalog vs information_schemaPostgreSQL 最核心的系统表是pg_class它记录了数据库中所有表、视图、索引、序列等对象的元数据。pg_namespace则存储命名空间也就是 schema的信息。我们查表名时通常把pg_class和pg_namespace做关联再用relkind字段过滤出普通表r或分区表p。而information_schema.tables是标准 SQL 提供的信息模式视图它更接近其他数据库比如 MySQL的查法字段含义一目了然table_schema、table_name、table_type等。它的好处是跨数据库通用性好坏处是查询效率通常比直接查系统表低一点而且某些 PostgreSQL 特有的对象类型比如分区表在信息模式里的展示方式需要额外注意。注意如果是日常临时查询用information_schema.tables就够了如果要写自动化脚本、批量处理大量对象我更推荐直接操作pg_catalog性能更稳信息也更全。2. 基于 LIKE 的查询实现从系统表到信息模式2.1 使用 pg_tables 和 pg_class 查询PostgreSQL 提供了一些视图比如pg_tables它就是对底层系统表的一个封装方便只查看普通表。用pg_tables查询表名包含特定字符串写法很简洁SELECT schemaname, tablename FROM pg_tables WHERE tablename LIKE %tablename% ORDER BY schemaname, tablename;这条 SQL 会返回所有 schema 下名字中包含tablename的表名。%是 SQL 通配符代表任意长度字符串包括零个字符。如果你想匹配以tablename开头就写tablename%结尾就是%tablename。如果你需要更底层的控制比如同时查出表的 owner 或者是否分区表就可以直接查pg_classSELECT n.nspname AS schema_name, c.relname AS table_name, c.relkind FROM pg_class c JOIN pg_namespace n ON n.oid c.relnamespace WHERE c.relname LIKE %tablename% AND c.relkind IN (r, p) ORDER BY n.nspname, c.relname;这里relkind r表示普通表p表示分区表。如果你不想看到分区表只保留r即可。oid是系统对象的唯一标识符c.relnamespace通过oid关联到pg_namespace这样才能拿到 schema 名。注意系统表里可能包含 PostgreSQL 自己维护的对象如pg_*开头的表如果不想看到它们可以加一个过滤条件n.nspname NOT LIKE pg_%。2.2 使用 information_schema.tables 查询用信息模式查表名是所有熟悉 SQL 标准的人最先想到的写法SELECT table_schema, table_name FROM information_schema.tables WHERE table_name LIKE %tablename% AND table_type BASE TABLE AND table_schema NOT IN (pg_catalog, information_schema) ORDER BY table_schema, table_name;这里我显式限制了table_type BASE TABLE把视图、外部表等对象排除掉。table_schema NOT IN (...)的作用是过滤掉系统自带的 schema避免把 PostgreSQL 内部对象也捞出来。实际使用中根据你的需求也可以改成table_type IN (BASE TABLE, VIEW)同时把视图也查出来。两种写法对比对比项pg_catalog / pg_tablesinformation_schema.tables标准兼容性PostgreSQL 专有SQL 标准过滤条件字段relkindtable_type性能较高略低可获取信息量非常丰富包括 oid、reloptions 等相对有限是否需要关联 schema需要手动 JOIN字段直接提供2.3 LIKE 模式匹配与转义细节LIKE 是 SQL 标准里的模式匹配操作符它只认识两个通配符%和_。_代表任意单个字符。如果你要匹配的表名本身包含%或_字符就需要转义否则查询结果会和你预期完全不一样。举个例子你想查表名里包含user_这个下划线的表直接写LIKE %user_%这里_会被当作“任意一个字符”于是userx、user1也会被匹配进来。正确的写法是指定转义字符SELECT table_name FROM information_schema.tables WHERE table_name LIKE %user\_% ESCAPE \ AND table_schema NOT IN (pg_catalog, information_schema);这里ESCAPE \明确告诉数据库反斜线是转义符所以\_表示“字面意义的下划线”。除此之外PostgreSQL 还支持更强大的正则匹配操作符~比如SELECT table_name FROM information_schema.tables WHERE table_name ~ user_[0-9]这个正则写法可以精确匹配user_后跟数字的表名但要注意正则匹配和 LIKE 匹配的性能差异。对绝大多数临时查询来说LIKE 已经足够。3. 借助 Qwen3.5-Plus 生成查询的自然语言实践3.1 如何向 AI 描述需求我之所以提到 Qwen3.5-Plus是因为这类需求用自然语言描述非常方便而且生成结果往往能给你一些意想不到的细节。比如你可以直接问“在 PostgreSQL 里帮我写一条 SQL找出所有表名中包含字符串tablename的表要排除系统表。” Qwen3.5-Plus 通常会在几秒钟内给出类似information_schema.tables的答案还会附带说明。如果你不满足于临时查询继续追问“改成用 pg_catalog 写并且要支持动态拼接 DROP 语句”它也能立即补充对应的 SQL。向 AI 描述需求时越具体越好。不要只说“帮我查表名”要明确数据库类型PostgreSQL、匹配方式前缀/后缀/中间包含、是否需要排除系统 schema、是否需要返回表的所有者、大小写是否敏感。这些信息直接决定了最终 SQL 的形态。注意AI 生成的 SQL 不一定完全符合你的环境。比如它默认所有参数字段都存在但如果你用的是老版本 PostgreSQL某些字段可能没有或者它给你的信息模式写法不包含table_schema过滤导致查出一堆系统表。所以 AI 给出的代码必须经过人工复核这也是我后面要强调的。3.2 从生成结果到实际执行的检查清单拿到 Qwen3.5-Plus 生成的 SQL 后我建议按这份清单逐项核对是否包含了table_schema或schemaname的过滤如果没有很可能会把pg_catalog里的系统表也查出来。是否使用了合适的匹配模式LIKE %tablename%和LIKE tablename%结果完全不同先确认你到底想要哪种。大小写是否敏感PostgreSQL 的表名在没有引号的情况下会被转成小写存储。如果你的库里有大小写混合的表名建表时用了双引号LIKE 默认规则会比较吃紧。是否考虑了权限普通用户只能看到自己有权限访问的表。如果连到的账号不是超级用户查询结果可能不全。执行前是否先加LIMIT或先SELECT count(*)验证这一步能避免一次性返回大量数据也能快速确认过滤条件是否符合预期。把这份清单当成“AI 辅助开发的必备防线”可以大幅减少生成 SQL 带来的潜在风险。4. 进阶动态 SQL 与自动化运维场景4.1 批量生成 ALTER TABLE 或 DROP TABLE 语句运维场景里找到这些表往往不是终点而是起点。比如你想把一批名字带tablename的旧表统一加个前缀或者想把它们移动到另一个 schema甚至直接删除。手动一条条写显然不现实正确做法是让 PostgreSQL 根据查询结果动态生成 SQL。举个例子把查到的表名拼接成ALTER TABLE ... RENAME TO ...语句SELECT ALTER TABLE || quote_ident(n.nspname) || . || quote_ident(c.relname) || RENAME TO || quote_ident(c.relname || _old) || ; AS ddl FROM pg_class c JOIN pg_namespace n ON n.oid c.relnamespace WHERE c.relname LIKE %tablename% AND c.relkind IN (r, p) AND n.nspname NOT IN (pg_catalog, information_schema);这里我用quote_ident函数对 schema 名和表名做“标识符引用”目的是防止特殊字符破坏 SQL 结构。比如表名是my-table如果不加引号生成的 DDL 会变成ALTER TABLE my-table ...语法直接报错加上双引号后才是合法的标识符。这一点在拼接动态语句时特别重要也是一些初级脚本容易忽略的地方。你还可以在此基础上加条件只生成某些 schema 下的表或者通过ORDER BY控制执行顺序。把生成的 DDL 输出到文本文件再人工审核后批量执行这是比较稳妥的自动化方式。4.2 结合存储过程实现自动化清理如果想在数据库内部完成“找到旧表 - 备份 - 清理”全流程可以写一个 PL/pgSQL 存储过程。下面是一个简化示例把匹配到的表名保存到临时表里然后用FOR循环逐条处理。DO $$ DECLARE r record; table_count int; BEGIN SELECT count(*) INTO table_count FROM pg_class c JOIN pg_namespace n ON n.oid c.relnamespace WHERE c.relname LIKE %tablename% AND c.relkind IN (r, p) AND n.nspname NOT IN (pg_catalog, information_schema); RAISE NOTICE 找到 % 张表, table_count; FOR r IN SELECT n.nspname AS schema_name, c.relname AS table_name FROM pg_class c JOIN pg_namespace n ON n.oid c.relnamespace WHERE c.relname LIKE %tablename% AND c.relkind IN (r, p) AND n.nspname NOT IN (pg_catalog, information_schema) LOOP RAISE NOTICE 处理表: %.%, r.schema_name, r.table_name; -- 这里可以执行备份、删除或修改操作 -- 例如: EXECUTE format(DROP TABLE %I.%I, r.schema_name, r.table_name); END LOOP; END $$;这个示例里的EXECUTE format(DROP TABLE %I.%I, ...)是执行动态 SQL 的常用方式%I会被替换为经过引号处理的标识符避免 SQL 注入和语法错误。实际应用中我不会直接写 DROP而是先备份或者做 rename等观察几天没问题再清理。5. 常见问题与排查技巧实录5.1 权限不足看不到表如果你用普通账号执行查询可能发现结果比自己预想的少。这是因为 PostgreSQL 的元数据可见性和对象权限绑定。比如你只能看到自己拥有权限的表或者通过某个角色间接授权的表。这时可以切换到超级用户、或者拥有pg_read_all_data等角色的账号再查也可以检查search_path是否包含了你期望的 schema。排查方法很简单先看当前用户和目标表的权限关系使用\dp命令或查询information_schema.table_privileges。如果确实需要普通用户能查到所有表名可以考虑在 schema 级别授予USAGE权限不过要谨慎评估安全影响。5.2 LIKE 大小写敏感与 collationPostgreSQL 的 LIKE 匹配是否大小写敏感取决于目标列的 collation排序规则。一般来说PostgreSQL 默认的 collation 是大小写敏感的所以LIKE %Tablename%只会匹配到Tablename而不会匹配tablename。你可以在查询时指定表达式的大小写不敏感SELECT table_name FROM information_schema.tables WHERE table_name ILIKE %tablename%ILIKE是 PostgreSQL 提供的不区分大小写的 LIKE 变体。如果你希望匹配任意大小写组合用ILIKE最方便。但要注意ILIKE在过滤大量数据时性能会比 LIKE 差一些因为无法高效利用索引。5.3 误匹配与正则替代方案LIKE 的%通配符会匹配任意长度的字符串但如果你对“特定字符串”的边界有要求比如只匹配“单词”而不是“单词的一部分”LIKE %tablename%就会把my_tablename_temp、tablename_backup都匹配出来这可能不是你想要的。这时候可以结合正则表达式~用单词边界符table_name ~ \mtablename\MPostgreSQL 支持\m匹配单词开头\M匹配单词结尾。不过实际运维中表名里的分隔符通常就是下划线或数字我会先把匹配结果SELECT出来人工过目再决定下一步操作。5.4 关于 Qwen3.5-Plus 生成 SQL 的可靠性建议最后说说我对 AI 辅助写 SQL 的体会。Qwen3.5-Plus 确实能提升效率尤其适合这种“知道大概需求、但不确定具体系统表字段”的场景。它可以把pg_catalog和information_schema的各种差异讲得明明白白还能根据你的追问不断修正。但你要记住它生成的是“建议代码”不是“执行许可”。我通常的做法是让 AI 给出第一版 SQL我选择性地加入过滤系统表、排序、权限相关的条件然后在测试环境跑一遍确认结果集和预期的表数量一致了再拿到生产环境执行。这套流程虽然听起来慢实际上比“直接复制 AI 答案到生产库”稳妥得多能避免不少低级错误。另外因为 PostgreSQL 的版本差异某些系统表字段可能在你的版本里不存在。比如pg_class.relrowsecurity是较新版本才有的如果 AI 生成的 SQL 引用了它在旧版本上就会报错。所以遇到错误时把报错信息反馈给 AI让它重新调整往往比手动查文档更快。最后再分享一个小技巧如果你经常需要按表名特征做批量操作可以把常用的查询模板保存成.sql文件或数据库视图下次只需要改一下 LIKE 后面的关键字就能快速复用。我自己就在本地维护了十几个这样的模板配合 Qwen3.5-Plus 做日常补充基本能覆盖绝大多数元数据查询需求。如果你也在做类似的数据库治理工作不妨从今天这条LIKE查询开始建立一个属于你自己的模板库。
锦
锦皓数字建站
深耕本土企业品牌数字化升级,专注原创端正雅致商务官网,从视觉设计到稳定运维全程保驾护航。