#sql #optimization #presto
Вопрос:
Как я могу избавиться от этой рекурсивной функции замены регулярных выражений в приведенном ниже 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 шаблону
Комментарии:
1. Хотя вышесказанное не является рекурсивным, рекурсию можно использовать для итеративного применения
regexp_replace
со списком кортежей аргументов. См.: trino.io/docs/current/sql/select.html2. Извините. Если вы хотите применить только один шаблон к строке, вы можете
JOIN
в списке шаблонов применить только соответствующий шаблон, предполагая, что он совпадает.
Ответ №1:
Первый пример-без рекурсии, чтобы просто применить шаблон, соответствующий строке (предполагается, что будет соответствовать только один шаблон).:
list
это просто способ предоставить список замен.args
предоставляет строку для применения замен.doit
является ли логика, которая применяет только соответствующие шаблоны изlist
- Окончательное выражение запроса показывает результат для этих совпадающих случаев.
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
Если у вас есть версия presto (например , trino), которая поддерживает WITH RECURSIVE
, вот пример того, как рекурсию можно использовать для применения списков замен с переменным числом замен.
list
это просто способ предоставить список замен.args
предоставляет строку для применения замен.doit
является рекурсивной логикой, которая перебираетlist
- В конечном выражении запроса отображаются все результаты (от 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 с настройкой последнего шага:
- Окончательное выражение запроса просто захватывает последнюю версию замененной строки.
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