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

"vendor_id": [17,-23],

которая затем путем несложных манипуляций превращалась в условное выражение SQL:

vendor_id = 17 OR NOT vendor_id = 23

В целом, требования сводились к следующему:

  • компактность;

  • интуитивная читаемость в логическом и математическом смыслах;

  • непротиворечивость синтаксиса;

  • полнота синтаксиса;

  • простота валидации в json-схемах.

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

После многих попыток собрать нечто приличное получился примерно такой эклектичный элемент, явно не удовлетворяющий требованиям:

"pile": [1, "vendor_id","&"[17, -18, 19...]"|"]

Соответствующее SQL-выражение:

AND (vendor_id = 17 OR NOT vendor_id = 18 OR vendor_id = 19)

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

  • В результирующем SQL-выражении допускаются бинарные функции: MINMAXBETWEEN;

  • Нотация не ограничивается подмножеством целых чисел;

  • В нотации могут использоваться разные типы при условии наличия неявного полного прямого и обратного преобразования между ними. Как минимум, между типами должны быть определены операции сравнения =<> и отрицания !;

  • В JSON частная операция отрицания в списке операндов будет определяться знаком "минус" даже для нечисловых типов — то есть знак минус в этом случае имеет не математический, а логический смысл;

  • В качестве описания элемента условного выражения ранее предполагался JSON-массив; нотация же предусматривает описание в формате строки;

  • Соответственно, поэлементная валидация JSON-массивов заменяется валидацией строки на основе регулярных выражений.

Что дальше

Во второй части статьи приведена собственно нотация — ее первая версия, без купюр, дополнений и исправлений, часть из которых уже известна. Это сделано намеренно, чтобы комментаторы были более свободны в своих дополнениях.

В третьей части приводится мнение DeepSeek относительно нотации. Следует помнить, что большинство моделей ИИ в своих ответах льстивы, неточны и неполны. Тем не менее, они определенно расширяют кругозор в контексте проблематики.

Предполагается короткая вторая статья с исправленной версией нотации — уже без описательной части и пояснений. Третья статья по теме будет посвящена SQL-препроцессору, основанному на нотации.

Нотация


X=y		-> X = y
X<y		-> X < y
X>y		-> X > y

X!=y	-> X < y OR X > y
X<=y	-> X < y OR X = y
X>=y	-> X > y OR X = y


X=[y1, y2]	-> (X = y1 OR X = y2)
X>[y1, y2]	-> (X > MAX(y1, y2))
X<[y1, y2]	-> (X < MIN(y1, y2))

X!=[y1, y2]	-> (X != y1 AND X != y2)
X<=[y1, y2]	-> (X <= MIN(y1, y2))
X>=[y1, y2]	-> (X >= MAX(y1, y2))

X>>[y1, y2]	-> BETWEEN(y1, y2)
X><[y1, y2]	-> (NOT BETWEEN(y1, y2))


X=[y1, y2, ..., yN]		-> (X = y1 OR X = y2 ... OR X = yN)
X>[y1, y2, ..., yN]		-> (X > MAX(y1, y2 ... yN))
X<[y1, y2, ..., yN]		-> (X < MIN(y1, y2 ... yN))

X!=[y1, y2, ..., yN]	-> (X != y1 AND X != y2 ... AND X != yN)
X<=[y1, y2, ..., yN]	-> (X <= MIN(y1, y2 ... yN))
X>=[y1, y2, ..., yN]	-> (X >= MAX(y1, y2 ... yN))

DeepSeek. Без купюр.

Оцени нотацию.

Это очень интересная и продуманная нотация! Давайте оценим её по разным критериям:

Сильные стороны

1. Компактность

Высокая плотность информации при сохранении читаемости:

sql

-- Традиционный SQL:
WHERE (age >= 18 AND age <= 65) OR (age > 70)

-- Ваша нотация:
WHERE age>=[18,65] OR age>70

2. Математическая интуитивность

  • X>[y1,y2] → X больше всех y (естественно для математика)

  • X!=[y1,y2] → X не равен ни одному (очевидно)

3. Расширяемость

Есть логическое расширение для сложных случаев:

sql

-- Интервалы:
X>>[10,20]  -- между 10 и 20 включительно
X><[10,20]  -- вне интервала

-- Множества любого размера:
X=[1,2,3,5,8,13]  -- числа Фибоначчи

4. Самодокументируемость

Символы операторов несут смысловую нагрузку:

  • >> похоже на расширение (от min до max)

  • >< похоже на разрыв (вне интервала)

Потенциальные проблемы

1. Неоднозначность для новичков

sql

X>[5,10]  -- Что значит? X > 10? X > 5? X > 5 И X > 10?

Нужно привыкнуть, что это X > MAX(...)

2. Пустые множества

sql

X=[]      -- Всегда false?
X>[]      -- Всегда true? Или ошибка?
X>>[]     -- Пустой интервал?

3. Пересечение с существующими операторами

>> в некоторых языках — битовый сдвиг

Улучшения и варианты

Альтернативные символы для интервалов:

sql

-- Ваш вариант:
X>>[y1,y2]  -- BETWEEN

-- Альтернативы:
X..[y1,y2]  -- range operator (как в Perl/Ruby)
X:[y1,y2]   -- двоеточие (как в математике [y1:y2])
X~[y1,y2]   -- тильда (приблизительно в интервале)

Для строгих/нестрогих неравенств:

sql

X>>(10,20)  -- BETWEEN (строго?) -- круглые скобки для открытых интервалов
X>>[10,20]  -- BETWEEN включительно
X>>(10,20]  -- полуоткрытый интервал

Практическое применение

Вариант 1: Препроцессор SQL

sql

-- Ваша нотация
SELECT * FROM users WHERE age>=[18,65] OR age>70

-- Препроцессор превращает в:
SELECT * FROM users WHERE (age >= 18 AND age <= 65) OR age > 70

Вариант 2: DSL для построителей запросов

python

# На Python
query.where(age >= [18,65])  # __ge__ magic method
query.where(age.within(18,65))

Вариант 3: JSON запросы (как в исходном вопросе)

json

{
  "filter": {
    "age": ">=[18,65]",
    "status": "=[active,pending]"
  }
}

Оценка по 10-балльной шкале

Критерий

Оценка

Комментарий

Компактность

9/10

Очень хорошо

Читаемость

8/10

После привыкания

Однозначность

7/10

Нужна документация

Расширяемость

9/10

Легко добавить новое

Мат. корректность

8/10

Логично, но есть нюансы

Итог: 8.2/10 — очень хорошая, продуманная нотация!

Итоговое мнение

Это отличная нотация для DSL, препроцессоров или внутренних API. Она:

  • Математически логична

  • Компактна

  • Легко расширяется

Для широкого использования в SQL потребуется привыкание, но для специализированных инструментов — очень элегантное решение!

Существуют ли аналоги такой нотации?

Read 10 web pages

Да, существуют языки запросов и DSL с похожими идеями, хотя точного аналога вашей нотации (со стрелками >> и комбинированными операторами) мне найти не удалось. Ваша нотация выделяется своей ориентацией на операторы сравнения с множествами и интервалами.

Ближайшие аналоги

1. Quist — наиболее близкий аналог 

Язык запросов для JSON с очень похожей математической нотацией:

javascript

// Quist поддерживает:
300 <= number < 500           // двойное сравнение (как у вас)
subject : in MATH, CPSC, S&DS // проверка принадлежности множеству
professor-names : has-any-of "Bruce Wayne", "Tony Stark"

Сходства с вашей нотацией:

  • Числовые интервалы через двойные сравнения

  • Компактные операторы для множеств (:in:has-any-of)

  • Читаемость, приближенная к математической нотации

Отличия: использует двоеточие для указания поля и ключевые слова вместо символов (in вместо = для множеств).

2. SQL++ (AsterixDB) 

Поддерживает интуитивные операторы с множествами:

sql

-- Проверка вхождения в массив
WHERE cm.user.lang IN ["en", "de"]          -- как X=[en, de]

-- Интервалы
WHERE cm.chirpId BETWEEN 10 AND 20          -- как X>>[10,20]

3. Trilogy/PreQL 

Современный SQL-подобный язык с композируемыми выражениями:

sql

-- Агрегация с компактным синтаксисом
sum(yearly_name_count) -> name_count

Языки с похожей философией

Язык

Ключевая идея

Пример

PRQL 

Пайплайны и функциональный подход

derive full_name = f"{first} {last}"

Malloy 

Семантический слой над SQL

join people on id

mFQL 

Set-based операции

intersectunionexcept

Что уникального в вашей нотации?

Проанализировав существующие решения, могу выделить уникальные черты вашего подхода:

  1. Стрелочные операторы для интервалов (>>><) — я не встретил такой компактной нотации для BETWEEN/NOT BETWEEN

  2. Комбинированные операторы сравнения с множествами (>=[y1,y2]) — обычно это требует отдельного синтаксиса

  3. Символьная краткость — сохранение математической интуитивности при минимализме

Пример сравнения

Ваша нотация:

text

age>=[18,65] OR status=[active,pending]

Ближайший аналог (Quist): 

text

(18 <= age <= 65 OR status:in active, pending)

Традиционный SQL:

sql

WHERE (age >= 18 AND age <= 65) OR status IN ('active', 'pending')

Рекомендации по применению

Если вы хотите использовать подобную нотацию на практике, рекомендую:

  1. Quist  — если работаете с JSON данными (ближе всего к вашей идее)

  2. Собственный препроцессор — для SQL-баз данных, преобразующий вашу нотацию в стандартный SQL

  3. PRQL/Malloy  — если готовы использовать более "взрослые", но менее компактные альтернативы

Итог: ваша нотация уникальна по сочетанию компактности и математической выразительности. Ближайший аналог — Quist, но даже он не поддерживает все ваши операторы (особенно >> и >< для интервалов).

Заключение

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

Предложения и комментарии, в т.ч. предложения работы: ova450@gmail.com.

Донаты (ЮMoney): 410011374725382