我正在尝试清理 PostgreSQL 表中的数据,其中一些记录在email_address
(由于已修复的错误导致的挫败感,有问题的记录是由激动的用户输入的):
┌────────────────────┐ │ email_address │ ├────────────────────┤ │ foo@go.bar.me.net │ │ foo@foo.com │ │ foo@example.com │ │ baz@example.com │ │ barred@qux.com │ └────────────────────┘
所需的查询输出
我想构建一个查询,用亵渎分数注释数据表中的每一行,并按分数对记录进行排序,以便人类可以浏览带注释的数据(在网络应用程序中呈现)并采取必要的行动:
┌────────────────────┬────────┐ │ email_address │ 分数 │ ├────────────────────┼────────┤ │ foo@foo.com │ 18 │ │ foo@go.bar.me.net │ 14 │ │ foo@example.com │ 9 │ │ baz@example.com │ 3 │ │ barred@qux.com │ 0 │ └────────────────────┴────────┘
尝试#1
我正在采用的方法是建立一个正则表达式列表(现在我有 2 个问题......)和分数,如果在 email_address 列中找到该词,那么非常亵渎的词将贡献很大的亵渎分数。我的profanities
桌子看起来像这样:
┌──────────────────┬────────┐ │ profanity_regexp │ 分数 │ ├──────────────────┼────────┤ │ foo │ 9 │ │ bar(?!red) │ 5 │ │ 巴兹 │ 3 │ └──────────────────┴────────┘
横向连接
我发现我可以在函数上使用LATERAL
连接regexp_matches
来从每个函数中提取所有脏话email_address
(但没有脏话的记录会被丢弃):
SELECT
data.email_address,
array_agg(matches)
FROM
data,
profanities p,
LATERAL regexp_matches(data.email_address, p.posix_regexp, 'gi') matches
GROUP BY
data.email_address;
这会产生以下结果:
┌────────────────────┬────────────────────┐ │ email_address │ profanities_found │ ├────────────────────┼────────────────────┤ │ foo@foo.com │ {{foo},{foo}} │ │ foo@example.com │ {{foo}} │ │ foo@go.bar.me.net │ {{foo},{bar}} │ │ baz@example.com │ {{baz}} │ └────────────────────┴────────────────────┘
子选择
我还想出了如何使用以下 SQL 获取每条记录的亵渎分数小计数组:
SELECT
data.email_address,
array(
SELECT score * (
SELECT COUNT(*)
FROM (SELECT
regexp_matches(data.email_address, p.posix_regexp, 'gi')
) matches
)
FROM profanities p
) prof
from data;
正确地产生所有行(包括没有亵渎的行),如下所示:
┌────────────────────┬──────────┐ │ email_address │ 教授 │ ├────────────────────┼──────────┤ │ foo@go.bar.me.net │ {9,5,0} │ │ foo@foo.com │ {18,0,0} │ │ foo@example.com │ {9,0,0} │ │ baz@example.com │ {0,0,3} │ │ barred@qux.com │ {0,0,0} │ └────────────────────┴──────────┘
问题
如何对横向连接的结果求和以获得所需的输出?
我可以使用另一种策略来获得所需的结果吗?