Sql 如何在正则表达式上联接表

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

假设我有两个表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
但查询失败,出现错误:

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
    )