Sql 如何在正则表达式上联接表
假设我有两个表msg用于消息,mnc用于移动网络代码。 他们没有任何关系。但是我想加入他们Sql 如何在正则表达式上联接表,sql,regex,postgresql,join,pattern-matching,Sql,Regex,Postgresql,Join,Pattern Matching,假设我有两个表msg用于消息,mnc用于移动网络代码。 他们没有任何关系。但是我想加入他们 SELECT msg.message, msg.src_addr, msg.dst_addr, mnc.name, FROM "msg" JOIN "mnc" ON array_to_string(regexp_matches(msg.src_addr || '+' || msg.dst_addr, '38(...)'), '') = mnc.code 但查询失败,出现错误: p
SELECT msg.message,
msg.src_addr,
msg.dst_addr,
mnc.name,
FROM "msg"
JOIN "mnc"
ON array_to_string(regexp_matches(msg.src_addr || '+' || msg.dst_addr, '38(...)'), '') = mnc.code
但查询失败,出现错误:
psql:marketing.sql:28: ERROR: argument of JOIN/ON must not return a set
LINE 12: ON array_to_string(regexp_matches(msg.src_addr || '+' || msg...
有没有办法做到这一点?还是我走错了方向?您当前的问题是可能返回一行或多行。尝试使用“substring”,它根据正则表达式模式提取子字符串
SELECT msg.message,
msg.src_addr,
msg.dst_addr,
mnc.name
FROM "msg"
JOIN "mnc"
ON substring(msg.src_addr || '+' || msg.dst_addr from '38(...)') = mnc.code
正如@Milen已经提到的,
regexp\u matches()
可能是用于您的目的的错误函数。你想要一个简单的。实际上,速度会更快:
大概是最快的
此外,您只希望mnc.code
正好包含3个字符
使用regexp 您可以用正则表达式编写相同的代码,但速度肯定会慢一些。下面是一个与您的原始版本相近的工作示例:
SELECT msg.message
,msg.src_addr
,msg.dst_addr
,mnc.name
FROM mnc
JOIN msg ON (msg.src_addr || '+' || msg.dst_addr) ~ (38 || mnc.code)
AND length(mnc.code) = 3
这也要求msg.src_addr
和msg.dst_addr
为非空
第二个查询演示了附加检查length(mnc.code)=3
如何进入JOIN
条件或WHERE
子句。这里也有同样的效果
与regexp_匹配() 您可以通过以下方式实现此功能: 但相比之下,这将是缓慢的——至少我是这么认为的 说明:
regexp_matches()表达式只返回第一个匹配的所有捕获子字符串的数组。由于只捕获一个子字符串(模式中的一对括号),因此只会获得一个元素的数组 使用附加的“全局”开关
'g'
,您将获得所有匹配项,但会有多行。因此,您需要一个子选择来测试它们(或聚合)。把它放在一个存在的半联接中,你就得到了你想要的
也许你可以用这三种测试的性能测试来报告?
使用它。这可能是非常低效的(不使用索引,必须比较每一行)。@TheifMaster,不一定,它可以使用基于函数的索引,例如如何提到upper@z4y4ts,正则表达式38(…)
或者它只是一个正则表达式的示例?就我所见,它只是查找任何出现的38后跟任何3个其他字符。实际上,没有'g'
开关,regexp_matches()
只返回1行,其中包含第一个匹配的所有捕获子字符串的数组。但是,OP需要使用'g'
开关来获得所有匹配的结果。它可能会返回多行,这对解析器很重要,因此会出现错误消息。这将失败,因为substring()
只返回第一个匹配,但另一个匹配可能是mnc.code
。考虑:选择子字符串('38foo+38bar','38(…)')='bar'
。这可能就是OP尝试regexp\u matches()
的原因。您好@erwin,谢谢您的可靠回答。下面是一些性能数据,正如您所说,使用LIKE进行查询是最快的,其次是regexp和regexp_matches()。虽然没有什么意外,但我认为真实的数字会很有趣。@z4y4ts:谢谢你的反馈。完全符合预期,但验证总是好的。:)
SELECT msg.message
,msg.src_addr
,msg.dst_addr
,mnc.name
FROM mnc
JOIN msg ON (msg.src_addr || '+' || msg.dst_addr) ~ (38 || mnc.code)
AND length(mnc.code) = 3
SELECT msg.message
,msg.src_addr
,msg.dst_addr
,mnc.name
FROM mnc
JOIN msg ON EXISTS (
SELECT *
FROM regexp_matches(msg.src_addr ||'+'|| msg.dst_addr, '38(...)', 'g') x(y)
WHERE y[1] = mnc.code
)