При решении одной прикладной задачи возникла необходимость формировать довольно длинные условные выражения в 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-выражении допускаются бинарные функции:
MIN,MAX,BETWEEN;Нотация не ограничивается подмножеством целых чисел;
В нотации могут использоваться разные типы при условии наличия неявного полного прямого и обратного преобразования между ними. Как минимум, между типами должны быть определены операции сравнения
=,<,>и отрицания!;В 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 | Пайплайны и функциональный подход |
|
Malloy | Семантический слой над SQL |
|
mFQL | Set-based операции |
|
Что уникального в вашей нотации?
Проанализировав существующие решения, могу выделить уникальные черты вашего подхода:
Стрелочные операторы для интервалов (
>>,><) — я не встретил такой компактной нотации для BETWEEN/NOT BETWEENКомбинированные операторы сравнения с множествами (
>=[y1,y2]) — обычно это требует отдельного синтаксисаСимвольная краткость — сохранение математической интуитивности при минимализме
Пример сравнения
Ваша нотация:
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')
Рекомендации по применению
Если вы хотите использовать подобную нотацию на практике, рекомендую:
Quist — если работаете с JSON данными (ближе всего к вашей идее)
Собственный препроцессор — для SQL-баз данных, преобразующий вашу нотацию в стандартный SQL
PRQL/Malloy — если готовы использовать более "взрослые", но менее компактные альтернативы
Итог: ваша нотация уникальна по сочетанию компактности и математической выразительности. Ближайший аналог — Quist, но даже он не поддерживает все ваши операторы (особенно >> и >< для интервалов).
Заключение
Надеюсь на конструктивные комментарии вплоть до предложения полной отмены данной нотации с последующей заменой на аналогичную существующую.
Предложения и комментарии, в т.ч. предложения работы: ova450@gmail.com.
Донаты (ЮMoney): 410011374725382
