假设我有两个消息表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...
有没有办法进行此类加入?还是我走错路?
答案 0 :(得分:14)
正如@Milen已经提到的regexp_matches()
可能是错误的功能。你想要一个简单的regular expression match (~
)。实际上,LIKE operator (~~
)将更快:
SELECT msg.message
,msg.src_addr
,msg.dst_addr
,mnc.name
FROM mnc
JOIN msg ON msg.src_addr ~~ ('%38' || mnc.code || '%')
OR msg.dst_addr ~~ ('%38' || mnc.code || '%')
WHERE length(mnc.code) = 3
此外,您只需要{3}个字符的mnc.code
。
你可以用正则表达式编写相同内容,但它肯定会慢一些。这是一个接近原文的工作示例:
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
为NOT NULL
。
第二个查询演示了附加检查length(mnc.code) = 3
如何进入JOIN
条件或WHERE
子句。这里效果相同。
你可以使用regexp_matches()
:
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
)
但相比之下它会很慢 - 或者我认为。
<强>解释强>
你的regexp_matches()表达式只返回第一个匹配的所有捕获的子串的数组。由于您只捕获一个子字符串(模式中的一对括号),因此您将只使用一个元素来获得数组。
您使用其他“全局”开关 'g'
所有匹配 - 但是在多行中。所以你需要一个子选择来测试它们(或聚合)。把它放在EXISTS
- 半连接中,你得到你想要的东西。
也许您可以通过所有三个效果测试报告回来? 请使用EXPLAIN ANALYZE。
答案 1 :(得分:0)
您的直接问题是regexp_matches
可能会返回一行或多行。
答案 2 :(得分:0)
尝试使用“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