Обновление: я обновил тестовую строку, чтобы охватить случай, который я пропустил.
Я пытаюсь подсчитать количество фильтров WHERE
в запросе, используя регулярное выражение.
Таким образом, общая идея состоит в том, чтобы подсчитать количество WHERE
и AND
, встречающихся в запросе, исключая AND
, который происходит после JOIN
и перед WHERE
. А также исключая AND
, который встречается в предложении CASE WHEN
.
Например, этот запрос:
WITH cte AS (\nSELECT a,b\nFROM something\nWHERE a>10\n AND b<5)\n, cte2 AS (\n SELECT c,\nd FROM another\nWHERE c>10\nAND d<5)\n SELECT CASE WHEN c1.a=1\nAND c2.c=1 THEN 'yes' ELSE 'no' \nEND,c1.a,c1.b,c2.c,c2.d\nFROM cte c1\nINNER JOIN cte2 c2 ON c1.a = c2.c\nAND c1.b = c2.d\nWHERE c1.a<4 AND DATE(c1)>'2022-01-01'\nAND c2.c>6
-- FORMATTED FOR EASE OF READ. PLEASE USE LINE ABOVE AS REGEX TEST STRING
WITH cte AS (
SELECT a,b
FROM something
WHERE a>10
AND b<5
)
, cte2 AS (
SELECT c,d
FROM another
WHERE c>10
AND d<5
)
SELECT
CASE
WHEN c1.a=1 AND c2.c=1 THEN 'yes'
WHEN c1.a=1 AND c2.c=1 THEN 'maybe'
ELSE 'no'
END,
c1.a,
c1.b,
c2.c,
c2.d
FROM cte c1
INNER JOIN cte2 c2
ON c1.a = c2.c
AND c1.b = c2.d
WHERE c1.a<4
AND DATE(c1)>'2022-01-01'
AND c2.c>6
должен вернуть 7
, а именно:
WHERE a>10
AND b<5
WHERE c>10
AND d<5
WHERE c1.a<4
AND DATE(c1)>'2022-01-01'
AND c2.c>6
Порция AND c1.b = c2.d
не считается, потому что она происходит после JOIN
, до WHERE
.
Часть AND c2.c=1
не считается, потому что она находится в пункте CASE WHEN
.
В конечном итоге я планирую использовать это в запросе Postgresql для подсчета количества фильтров, которые происходят во всех запросах за определенный период.
Я пытался найти ответ и попробовать сам, но безрезультатно. Поэтому ищу помощи здесь. Заранее благодарю!
@RichardHuxton, что вы подразумеваете под «базовым» разбором? если есть способ извлечь все предложения WHERE
в запросе, я буду более чем счастлив продолжить.
Вы можете попробовать что-то вроде этого:
WITH DataSource (parts) AS
(
SELECT REGEXP_MATCHES(
'WITH cte AS (SELECT a,b FROM something WHERE a>10 AND b<5)\n, cte2 AS (SELECT c,d FROM another WHERE c>10 AND d<5)\n SELECT c1.a,c1.b,c2.c,c2.d FROM cte c1 INNER JOIN cte2 c2 ON c1.a = c2.c AND c1.b = c2.d WHERE c1.a<4 AND c2.c>6',
E'(?= WHERE)[^)|;]+'
,'gmi'
)
)
SELECT SUM
(
(length(parts[1]) - length(REPLACE(parts[1], 'AND', ''))) / 3 -- counting ANDs
+ 1 -- for the where
)
FROM DataSource
Идея состоит в том, чтобы сопоставить текст после предложения WHERE
:
а затем просто подсчитайте AND и добавьте один из-за совпадения WHERE.
Спасибо! Ответ действительно близок, но он пропустил некоторые случаи (мой плохой, моя тестовая строка выше была недостаточно полной). Он не мог обрабатывать случаи, когда в предложении фильтра )
есть закрывающая скобка WHERE
. Пример: WHERE a>1 AND DATE(b)>'2023-01-01' AND c>4
. Я изменил свою тестовую строку, чтобы скрыть эту слабость. Приносим извинения за изменения.
Это работает, если у меня есть SELECT 'WHERE IS THE ANSWER?''
или SELECT thing FROM some_table WHERE condition ORDER BY (col_a || ' AND ' || col_b)
?
@RichardHuxton Я думаю, что нет, но, судя по тому, что я вижу в своих примерах, те, которые вы предложили, являются своего рода пограничными случаями, поэтому я согласен с тем, что регулярное выражение не работает для ваших случаев. Ваше здоровье.
Я стараюсь держаться подальше от просмотров назад, так как они могут быть грязными и слишком болезненными для использования, особенно с ограничением фиксированной ширины утверждения взгляда назад.
Предлагаемое мной решение состоит в том, чтобы зафиксировать все сценарии в разных группах, а затем выбрать только интересующую группу. Нежелательные сценарии по-прежнему будут сопоставляться, но не будут выбраны.
JOIN
(нежелательно)WHERE
(желательно)CASE
(нежелательно)(JOIN.*?(?=$|WHERE|JOIN|CASE|END))|(WHERE.*?(?=$|WHERE|JOIN|CASE|END))|(CASE.*?(?=$|WHERE|JOIN|CASE|END))
Примечание. Не стесняйтесь заменять WHERE|JOIN|CASE|END
на любое ключевое слово, которое вы хотите использовать в качестве «стопорных».
Все сценарии, включая нежелательные, будут сопоставлены, но вам нужно выбрать только группу 2 (выделена оранжевым цветом).
Это кажется хорошим решением. Только один он не мог поймать, если запросы использовали подзапросы вместо cte. Тем не менее, я думаю, что это хорошо на данный момент. Спасибо!
Regex - неправильный инструмент для этой работы. Будет очень сложно справиться со всеми пограничными случаями (агрегированные фильтры, текстовые значения со словом «где» — два очевидных). Если вы действительно хотите получить точный подсчет, вам придется выполнить базовый анализ. Если вы можете извлечь только предложения where, это облегчит задачу.