sql - 将子字符串与存储的字符串列表匹配
问题描述
因此,在最近的 Twitch 泄露事件之后,每个人都在讨论他们最喜欢的错误代码。突出的一点是一个用于发现“非法术语”的怪物 SQL 语句。这让我开始思考如何“正确”地实现这一点。
所以你有一个字符串表,你想匹配子字符串,你如何在 PL/pgSQL 中编写它?我假设任何 SQL 实现都应该具有为此类元编程创建函数/过程的过程能力,基本上创建和执行 SQL,如下所示:
admin@localhost:words> SELECT 'XabcY' LIKE '%abc%' OR 'XabcY' LIKE '%xyz%' as matches;
+-----------+
| matches |
|-----------|
| True |
+-----------+
所以更具体地说,给定 table 中的字符串列表disallowed
:
| illegal_string |
|----------------|
| stupid |
| witless |
| moron |
| commie-lover |
如果其中任何一个与给定字符串匹配,您将如何在 PL/pgSQL 中创建一个在执行时返回 true 的动态查询?它不需要ILIKE
在 Twitch 中使用来检查给定的单词是否包含子字符串,所以使用position
也很好,但它应该是使用gin
索引和诸如此类的高性能/可调整的。
相关问题。
解决方案
有两种可能:
- 你可以使用
LIKE ANY(array)
运算符
postgres=# select 'Ahoj' like any (ARRAY['Ah%', 'Na%']);
┌──────────┐
│ ?column? │
╞══════════╡
│ t │
└──────────┘
(1 row)
postgres=# select 'Nazdar' like any (ARRAY['Ah%', 'Na%']);
┌──────────┐
│ ?column? │
╞══════════╡
│ t │
└──────────┘
(1 row)
- 你可以使用正则表达式:
postgres=# select 'Ahoj' ~ '^(Ah|Na)';
┌──────────┐
│ ?column? │
╞══════════╡
│ t │
└──────────┘
(1 row)
postgres=# select 'Nazdar' ~ '^(Ah|Na)';
┌──────────┐
│ ?column? │
╞══════════╡
│ t │
└──────────┘
(1 row)
所以最后你不需要动态SQL。
也有 ANSI/SQL 语法:
postgres=# select 'Nazdar' similar to '(Ah|Na)%';
┌──────────┐
│ ?column? │
╞══════════╡
│ t │
└──────────┘
(1 row)
因此,您可以编写如下内容:
DECLARE pw text[];
BEGIN
pw := (SELECT array_agg('%' || disallowed || '%'
FROM disallowed);
IF EXISTS(SELECT * FROM foo WHERE c LIKE ANY (pw)) THEN
RAISE NOTICE 'there are some disallowed words';
END IF;
...
我不确定表演。在较大的表上,您需要三元索引,或者使用全文而不是子字符串搜索可能更好。
推荐阅读
- ruby-on-rails - Rails 端点性能 - 寻找什么?
- python - 非常具体的应用程序的递归算法(Python)
- spring - JPA/Spring/Hibernate/etc 中是否有类似于 JPA 的 @PrePersist 允许更改相关实体的功能?
- google-apps-script - 谷歌课堂表格
- swagger - Swagger - 属性名称约定
- python - 如何键入检查引用类的数据类函数?
- sql-server - SQL 配置中没有 sqlbrowser
- azure - 使用 Docker 构建的 Azure DevOps 变得越来越慢
- java - 如何使用数字或字母验证在 jtextfield 中键入下划线
- laravel - 在 Laravel 中,如何在 Route::middleware 组中使用“cannot”?