Подсчитайте количество фильтров WHERE в SQL-запросе с использованием регулярного выражения

Обновление: я обновил тестовую строку, чтобы охватить случай, который я пропустил.

Я пытаюсь подсчитать количество фильтров 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, а именно:

  1. WHERE a>10
  2. AND b<5
  3. WHERE c>10
  4. AND d<5
  5. WHERE c1.a<4
  6. AND DATE(c1)>'2022-01-01'
  7. AND c2.c>6

Порция AND c1.b = c2.d не считается, потому что она происходит после JOIN, до WHERE.

Часть AND c2.c=1 не считается, потому что она находится в пункте CASE WHEN.

В конечном итоге я планирую использовать это в запросе Postgresql для подсчета количества фильтров, которые происходят во всех запросах за определенный период.

Я пытался найти ответ и попробовать сам, но безрезультатно. Поэтому ищу помощи здесь. Заранее благодарю!

Regex - неправильный инструмент для этой работы. Будет очень сложно справиться со всеми пограничными случаями (агрегированные фильтры, текстовые значения со словом «где» — два очевидных). Если вы действительно хотите получить точный подсчет, вам придется выполнить базовый анализ. Если вы можете извлечь только предложения where, это облегчит задачу.

Richard Huxton 10.02.2023 08:05

@RichardHuxton, что вы подразумеваете под «базовым» разбором? если есть способ извлечь все предложения WHERE в запросе, я буду более чем счастлив продолжить.

Jialer Chew 10.02.2023 11:21
Стоит ли изучать PHP в 2023-2024 годах?
Стоит ли изучать PHP в 2023-2024 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
2
2
92
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Вы можете попробовать что-то вроде этого:

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. Я изменил свою тестовую строку, чтобы скрыть эту слабость. Приносим извинения за изменения.

Jialer Chew 10.02.2023 11:09

Это работает, если у меня есть SELECT 'WHERE IS THE ANSWER?'' или SELECT thing FROM some_table WHERE condition ORDER BY (col_a || ' AND ' || col_b)?

Richard Huxton 10.02.2023 11:47

@RichardHuxton Я думаю, что нет, но, судя по тому, что я вижу в своих примерах, те, которые вы предложили, являются своего рода пограничными случаями, поэтому я согласен с тем, что регулярное выражение не работает для ваших случаев. Ваше здоровье.

Jialer Chew 10.02.2023 12:05
Ответ принят как подходящий

Я стараюсь держаться подальше от просмотров назад, так как они могут быть грязными и слишком болезненными для использования, особенно с ограничением фиксированной ширины утверждения взгляда назад.

Предлагаемое мной решение состоит в том, чтобы зафиксировать все сценарии в разных группах, а затем выбрать только интересующую группу. Нежелательные сценарии по-прежнему будут сопоставляться, но не будут выбраны.

  1. Группа 1 - начинается с JOIN (нежелательно)
  2. Группа 2 - Начинается с WHERE (желательно)
  3. Группа 3 - Начинается с CASE (нежелательно)
(JOIN.*?(?=$|WHERE|JOIN|CASE|END))|(WHERE.*?(?=$|WHERE|JOIN|CASE|END))|(CASE.*?(?=$|WHERE|JOIN|CASE|END))

Примечание. Не стесняйтесь заменять WHERE|JOIN|CASE|END на любое ключевое слово, которое вы хотите использовать в качестве «стопорных».

Все сценарии, включая нежелательные, будут сопоставлены, но вам нужно выбрать только группу 2 (выделена оранжевым цветом).

Это кажется хорошим решением. Только один он не мог поймать, если запросы использовали подзапросы вместо cte. Тем не менее, я думаю, что это хорошо на данный момент. Спасибо!

Jialer Chew 12.02.2023 16:16

Другие вопросы по теме

Похожие вопросы

Заменить все символы до и после определенных символов
Разделить строку запятыми, но запятые в токене
Синтаксический анализ текста python для разделения списка на куски, включая предшествующие разделители
Средство форматирования ввода не допускает значение, когда оно должно
Удалите все строки между двумя строками с определенными шаблонами с помощью однострочного Perl и регулярных выражений
Перейти к регулярным выражениям или кешированию — что быстрее в долгосрочной перспективе?
Добавьте логическое значение функции года и замените трехбуквенный месяц на его номер месяца в массиве строк
Сопоставление шаблонов регулярных выражений с использованием аннотации @Pattern в Spring Boot
Выполнять несколько операций регулярных выражений в каждой строке текстового файла и сохранять извлеченные данные в соответствующем столбце
Как проверить, принадлежит ли дата, указанная в виде строки, к интервалу из 2 дат, указанных в другой строке?