redshift regex 获取多个匹配项并扩展行
Posted
技术标签:
【中文标题】redshift regex 获取多个匹配项并扩展行【英文标题】:redshift regex get multiple matches and expand rows 【发布时间】:2018-11-28 21:40:12 【问题描述】:我正在处理 AWS Redshift 上的 URL 提取。 URL 列如下所示:
url item origin
http://B123//ajdsb apple US
http://BYHG//B123 banana UK
http://B325//BF89//BY85 candy CA
我想要得到的结果是获取以 B 开头的系列,如果 URL 中有多个系列,还扩展行。
extracted item origin
B123 apple US
BYHG banana UK
B123 banana UK
B325 candy CA
BF89 candy CA
BY85 candy CA
我当前的代码是:
select REGEXP_SUBSTR(url, '(B[0-9A-Z]3)') as extracted, item, origin
from data
正则表达式部分运行良好,但我在提取多个值并将它们扩展到新行时遇到问题。我尝试使用REGEXP_MATCHES(url, '(B[0-9A-Z]3)', 'g')
,但 Redshift 上不存在函数 regexp_matches...
【问题讨论】:
至少,我想知道如何在一个字符串中找到多个匹配项。如果我在一行中获得多个 macthe 也没关系 【参考方案1】:我使用的解决方案相当丑陋,但达到了预期的效果。它涉及使用REGEXP_COUNT
确定一行中的最大匹配数,然后使用REGEXP_SUBSTR
将生成的数字表连接到查询。
-- Get a table with the count of matches
-- e.g. if one row has 5 matches this query will return 0, 1, 2, 3, 4, 5
WITH n_table AS (
SELECT
DISTINCT REGEXP_COUNT(url, '(B[0-9A-Z]3)') AS n
FROM data
)
-- Join the previous table to the data table and use n in the REGEXP_SUBSTR call to get the nth match
SELECT
REGEXP_SUBSTR(url, '(B[0-9A-Z]3)', 1, n) AS extracted,
item,
origin
FROM data,
n_table
-- Only keep non-null matches
WHERE n > 0
AND REGEXP_COUNT(url, '(B[0-9A-Z]3)') >= N
【讨论】:
这个解决方案真的很容易理解!谢谢。我已经在我的采样数据集上对此进行了测试。效果很好!我现在正在整个表上测试这个查询。 超级有用且简单!有人可以在where子句中解释N
吗?
假设一个示例 URL 有 3 个匹配项,匹配最多的 URL 有 5 个匹配项。在这种情况下,n_table
将保存值 0、1、2、3、4、5。但是,对于我们的示例 URL(有 3 个匹配项),我们只需要 n 值 1、2、3,因此需要 where 子句。颠倒过来可能更有意义,n <= REGEXP_COUNT(url, '(B[0-9A-Z]3)')
。我们说对于我们的案例有 3 个匹配项(REGEXP_COUNT
为我们的示例 URL 返回 3),我们希望 n 在生成输出时具有值 1,2,3。【参考方案2】:
IronFarm 的回答启发了我,虽然我想找到一个不需要交叉连接的解决方案。这是我想出的:
with
-- raw data
src as (
select
1 as id,
'abc def ghi' as stuff
union all
select
2 as id,
'qwe rty' as stuff
),
-- for each id, get a series of indexes for
-- each match in the string
match_idxs as (
select
id,
generate_series(1, regexp_count(stuff, '[a-z]3')) as idx
from
src
)
select
src.id,
match_idxs.idx,
regexp_substr(src.stuff, '[a-z]3', 1, match_idxs.idx) as stuff_match
from
src
join match_idxs using (id)
order by
id, idx
;
这会产生:
id | idx | stuff_match
----+-----+-------------
1 | 1 | abc
1 | 2 | def
1 | 3 | ghi
2 | 1 | qwe
2 | 2 | rty
(5 rows)
【讨论】:
请注意,generate_series()
实际上在 redshift 中不受支持,并且似乎仅适用于玩具示例。当我弄清楚如何最好地处理这个问题时会更新我的答案。
是的...我在 Redshift 上进行了测试,generate_series()
无法正常工作。但它仍然是 postgresql 的绝佳解决方案 ^ ^以上是关于redshift regex 获取多个匹配项并扩展行的主要内容,如果未能解决你的问题,请参考以下文章
亚马逊 Redshift 的 REGEXP_SUBSTR 中的“匹配但排除”
Redshift 在多个条件下加入,但仅在一个条件不匹配时返回