如何在所有表中搜索特定值(PostgreSQL)?
是否可以在 PostgreSQL 中搜索每个表的每一列特定值?
类似的问题可以在此处找到对于甲骨文来说。
Is it possible to search every column of every table for a particular value in PostgreSQL?
A similar question is available here for Oracle.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(10)
转储数据库的内容,然后使用 grep 怎么样?
相同的实用程序 pg_dump 可以在输出中包含列名称。只需将
--inserts
更改为--column-inserts
即可。这样您也可以搜索特定的列名称。但如果我正在寻找列名,我可能会转储模式而不是数据。How about dumping the contents of the database, then using
grep
?The same utility, pg_dump, can include column names in the output. Just change
--inserts
to--column-inserts
. That way you can search for specific column names, too. But if I were looking for column names, I'd probably dump the schema instead of the data.下面是一个 pl/pgsql 函数,用于查找任何列包含特定值的记录。
它将要搜索的文本格式的值、要搜索的表名数组(默认为所有表)和模式名称数组(默认为所有模式名称)作为参数。
它返回一个表结构,其中包含架构、表名称、列名称和伪列
ctid
(表中行的非持久物理位置,请参阅 系统列)另请参阅 github 上的版本 基于相同的原理,但增加了一些速度和报告改进。
在测试数据库中使用的示例:
变体
要测试正则表达式而不是严格相等(例如 grep),查询的这一部分:
从 %I.%I WHERE 中选择 ctid (%I as text)=%L
可以更改为:
SELECT ctid FROM %I.%I WHERE cast(%I as text) ~ %L
对于不区分大小写的比较,您可以编写:
SELECT ctid FROM %I.%I WHERE lower(cast(%I as text)) = lower(%L)
Here's a pl/pgsql function that locates records where any column contains a specific value.
It takes as arguments the value to search in text format, an array of table names to search into (defaults to all tables) and an array of schema names (defaults all schema names).
It returns a table structure with schema, name of table, name of column and pseudo-column
ctid
(non-durable physical location of the row in the table, see System Columns)See also the version on github based on the same principle but adding some speed and reporting improvements.
Examples of use in a test database:
Variants
To test against a regular expression instead of strict equality, like grep, this part of the query:
SELECT ctid FROM %I.%I WHERE cast(%I as text)=%L
may be changed to:
SELECT ctid FROM %I.%I WHERE cast(%I as text) ~ %L
For case insensitive comparisons, you could write:
SELECT ctid FROM %I.%I WHERE lower(cast(%I as text)) = lower(%L)
假设:
regclass
) 和元组 ID (ctid
),因为这最简单。 (您可以轻松适应返回您想要的任何内容。)这是一种非常简单、快速且有点肮脏的方法:
如果未指定模式,则搜索整个数据库:(系统模式始终被排除。)
仅对于给定模式:
提供搜索模式,不包含
%
。您可能想要转义模式中的特殊字符。请参阅:
为什么“有点脏”?
如果
text
表示中的行的分隔符和修饰符可以是搜索模式的一部分,则可能会出现误报。特殊字符有:,
默认情况下()
"
\
可以添加为转义字符另外,某些列的文本表示可能取决于本地设置 - 但这种歧义是问题所固有的,而不仅仅是我的解决方案
返回每个符合条件的行<。仅一次,即使它匹配多次(与此处的其他答案相反)
搜索整个数据库通常需要很长时间才能完成< /em>。您可能想要限制某些模式/表(甚至列),如其他答案中所示。或者添加通知和进度指示器,这也在另一个答案中演示了
。类型表示为表名,在必要时根据当前
search_path
进行模式限定:什么是 <代码>ctid?
您可能希望在搜索模式中转义具有特殊含义的字符。请参阅:
Assuming:
regclass
) and the tuple ID (ctid
), because that's simplest. (You can easily adapt to return whatever you want.)Here is a dead simple, fast, and slightly dirty way:
If no schema is specified, the whole DB is searched: (System schemas are always excluded.)
For a given schema only:
Provide the search pattern without enclosing
%
.You may want to escape special characters in the pattern. See:
Why "slightly dirty"?
If separators and decorators for the row in
text
representation can be part of the search pattern, there can be false positives. Special characters are:,
by default()
"
\
may be added as escape charPlus, the text representation of some columns may depend on local settings - but that ambiguity is inherent to the question, not just to my solution.
Each qualifying row is returned once only, even when it matches multiple times (as opposed to other answers here).
Searching the whole DB typically takes a long time to finish. You might want to restrict to certain schemas / tables (or even columns) like demonstrated in other answers. Or add notices and a progress indicator, also demonstrated in another answer.
The
regclass
object identifier type is represented as table name, schema-qualified where necessary to disambiguate according to the currentsearch_path
:What is the
ctid
?You might want to escape characters with special meaning in the search pattern. See:
有一种方法可以在不创建函数或使用外部工具的情况下实现此目的。通过使用 Postgres 的
query_to_xml()
函数(可以在另一个查询中动态运行一个查询),可以跨多个表搜索文本。这是基于我的答案检索所有表的行数:搜索字符串
foo
在架构中的所有表中,可以使用以下内容:请注意,使用
xmltable
需要 Postgres 10 或更高版本。对于较旧的 Postgres 版本,也可以使用 xpath() 来完成。公共表表达式 (
WITH ...
) 只是为了方便而使用。它循环访问public
架构中的所有表。对于每个表,通过query_to_xml()
函数运行以下查询:where 子句用于确保仅针对包含搜索字符串的行生成昂贵的 XML 内容。这可能会返回如下内容:
完整行到 jsonb 的转换已完成,以便在结果中可以看到哪个值属于哪一列。
上面的代码可能会返回如下内容:
Postgres 10+ 的在线示例
旧版 Postgres 的在线示例
There is a way to achieve this without creating a function or using an external tool. By using Postgres'
query_to_xml()
function that can dynamically run a query inside another query, it's possible to search a text across many tables. This is based on my answer to retrieve the rowcount for all tables:To search for the string
foo
across all tables in a schema, the following can be used:Note that the use of
xmltable
requires Postgres 10 or newer. For older Postgres version, this can be also done using xpath().The common table expression (
WITH ...
) is only used for convenience. It loops through all tables in thepublic
schema. For each table the following query is run through thequery_to_xml()
function:The where clause is used to make sure the expensive generation of XML content is only done for rows that contain the search string. This might return something like this:
The conversion of the complete row to
jsonb
is done, so that in the result one could see which value belongs to which column.The above might return something like this:
Online example for Postgres 10+
Online example for older Postgres versions
如果您使用 IntelliJ 将数据库添加到数据库视图,然后右键单击数据库并选择全文搜索,它将列出您的特定文本的所有表和所有字段。
If you're using IntelliJ add your DB to Database view then right click on databases and select full text search, it will list all tables and all fields for your specific text.
无需存储新过程,您就可以使用代码块并执行来获取事件表。您可以按架构、表或列名称过滤结果。
Without storing a new procedure you can use a code block and execute to obtain a table of occurences. You can filter results by schema, table or column name.
如果有人认为这有帮助。这是@Daniel Vérité 的函数,其中另一个参数接受可在搜索中使用的列名称。这样就减少了处理时间。至少在我的测试中它减少了很多。
下面是上面创建的 search_function 的使用示例。
And if someone think it could help. Here is @Daniel Vérité's function, with another param that accept names of columns that can be used in search. This way it decrease the time of processing. At least in my test it reduced a lot.
Bellow is an example of usage of the search_function created above.
这是@Daniel Vérité 的带有进度报告功能的函数。
它以三种方式报告进展情况:
{要搜索的总列数}降至 0;
位于 c:\windows\temp\{progress_seq}.txt。
_
Here's @Daniel Vérité's function with progress reporting functionality.
It reports progress in three ways:
{total number of colums to search in} down to 0;
located in c:\windows\temp\{progress_seq}.txt.
_
-- 下面的函数将列出数据库中包含特定字符串的所有表
-- 迭代数据库中的所有表
-- 返回满足条件的表的数量。
-- 例如,如果表的任何字段中存在预期文本,
-- 那么计数就会大于0。我们可以找到通知
-- 在 postgres 数据库结果查看器的消息部分。
--获取每个表的字段。使用表的所有列构建 where 子句。
-- Below function will list all the tables which contain a specific string in the database
--Iterates through all the tables in the database
-- Returns the count of tables for which the condition is met.
-- For example, if the intended text exists in any of the fields of the table,
-- then the count will be greater than 0. We can find the notifications
-- in the Messages section of the result viewer in postgres database.
--Get the fields of each table. Builds the where clause with all columns of a table.
希望这会对某人有所帮助
我已经在 PostgreSQL 14 上的 DBeaver 中检查过这一点,并且它可以进行
Hope, this will help somebody
I've checked this in DBeaver on PostgreSQL 14, and it've worked