【问题标题】:Alternative to recursive regex replace query in prestopresto 中递归正则表达式替换查询的替代方法
【发布时间】:2021-10-31 15:05:03
【问题描述】:

如何使用更优雅的 SQL 设计模式摆脱以下 presto SQL 查询中的递归正则表达式替换函数?

SELECT
regexp_replace(
    regexp_replace(
        regexp_replace(
            regexp_replace(
                url, 
                'pattern1', 'replacement1'
            ), 
            'pattern2', 'replacement2'
        ), 
        'pattern3', 'replacement3'
    ), 
    'pattern4', 'replacement4'
) AS deidentified_url
FROM user_requests_tb

我们可以假设每个 url 只匹配 1 个模式

【问题讨论】:

  • 虽然上面不是递归的,但递归可用于迭代地应用 regexp_replace 与参数元组列表。见:trino.io/docs/current/sql/select.html
  • 对不起。如果您只想为每个字符串应用一个模式,您可以在模式列表上 JOIN 以仅应用匹配的模式,假设一个匹配。

标签: sql optimization presto


【解决方案1】:

第一个例子没有递归,只应用匹配字符串的模式(假设只有一个模式会匹配):

  1. list 只是提供替换列表的一种方式。
  2. args 提供了一个字符串来应用替换。
  3. doit 是仅应用来自 list 的匹配模式的逻辑
  4. 最终的查询表达式会显示匹配案例的结果。
WITH list (id, arg1, arg2) AS (
        SELECT 1, 'c1', 'x' UNION
        SELECT 2, 'd1', 'x' UNION
        SELECT 3, 'e1', 'x' UNION
        SELECT 4, 'f1', 'x' UNION
        SELECT 5, 'g1', 'x' UNION
        SELECT 6, 'h1', 'x'
     )
   , args (start_str) AS (
        SELECT 'abcde1fghijklmnop'
     )
   , doit (str) AS (
        SELECT regexp_replace(start_str, arg1, arg2)
          FROM args
          JOIN list
            ON regexp_like(args.start_str, list.arg1)
     )
SELECT * FROM doit
;

结果:

+------------------+
| str              |
+------------------+
| abcdxfghijklmnop |
+------------------+
1 row in set

如果您有支持 WITH RECURSIVE 的 presto 版本(如 trino),这里有一个示例,说明如何使用递归来应用具有可变数量替换的替换列表。

  1. list 只是提供替换列表的一种方式。
  2. args 提供了一个字符串来应用替换。
  3. doit 是迭代 list 的递归逻辑
  4. 最终查询表达式显示所有结果(0、1 到 n)。
WITH RECURSIVE list (id, arg1, arg2) AS (
        SELECT 1, 'c', 'x' UNION
        SELECT 2, 'd', 'x' UNION
        SELECT 3, 'e', 'x' UNION
        SELECT 4, 'f', 'x' UNION
        SELECT 5, 'g', 'x' UNION
        SELECT 6, 'h', 'x'
     )
   , args (start_str) AS (
        SELECT 'abcdefghijklmnop'
     )
   , doit (n, str) AS (
        SELECT 0  , start_str FROM args UNION ALL
        SELECT n+1, regexp_replace(str, arg1, arg2)
          FROM doit
          JOIN list
            ON list.id = n+1
     )
SELECT * FROM doit
 ORDER BY n
;

结果:

+------+------------------+
| n    | str              |
+------+------------------+
|    0 | abcdefghijklmnop |
|    1 | abxdefghijklmnop |
|    2 | abxxefghijklmnop |
|    3 | abxxxfghijklmnop |
|    4 | abxxxxghijklmnop |
|    5 | abxxxxxhijklmnop |
|    6 | abxxxxxxijklmnop |
+------+------------------+
7 rows in set

与上一步调整相同的 SQL:

  1. 最终的查询表达式只获取被替换字符串的最后一个版本。
WITH RECURSIVE list (id, arg1, arg2) AS (
        SELECT 1, 'c', 'x' UNION
        SELECT 2, 'd', 'x' UNION
        SELECT 3, 'e', 'x' UNION
        SELECT 4, 'f', 'x' UNION
        SELECT 5, 'g', 'x' UNION
        SELECT 6, 'h', 'x'
     )
   , args (start_str) AS (
        SELECT 'abcdefghijklmnop'
     )
   , doit (n, str) AS (
        SELECT 0  , start_str FROM args UNION ALL
        SELECT n+1, regexp_replace(str, arg1, arg2)
          FROM doit
          JOIN list
            ON list.id = n+1
     )
SELECT * FROM doit
 ORDER BY n DESC
 LIMIT 1
;

结果:

+------+------------------+
| n    | str              |
+------+------------------+
|    6 | abxxxxxxijklmnop |
+------+------------------+
1 row in set

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2016-03-24
    • 1970-01-01
    • 2018-01-10
    • 2020-11-30
    • 1970-01-01
    • 2016-01-23
    • 1970-01-01
    相关资源
    最近更新 更多