Обновить

Комментарии 16

Если вы хотите сделать удобную запись выражений в виде JSON, то посмотрите на префиксную нотацию, используемую в QueryBuilder фреймворков Yii 1.1 или Yii 2. Вот она и на JSON прекрасно ложится, и специалистами легко читается.

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

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

x ∈ [y1, y2) → x >= y1 AND x < y2

По моему опыту, это бывает удобнее, чем BETWEEN. Например, если нужны все сутки 13 января 2026 года, а столбец dt имеет формат DATETIME(6) (MySQL), то выражение с BETWEEN будет выглядеть так:

dt BETWEEN '2026-01-13' AND '2026-01-13 23:59:59.999999'

, а выражение с открытым справа диапазоном так:

dt >= '2026-01-13' AND dt < '2026-01-14'

N.B. Да, нейросеть предложила реализовать все 4 варианта, но варианты (] и () встречаются куда реже, чем [] и [).

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

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

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

X>=y -> X > y OR X = y

Использовать два сравнения и OR бессмысленно, т.к. операции <=, >=, != (синоним <>) уже есть в SQL.

NOT vendor_id = 23

Данная конструкция в точности равна:

vendor_id <> 23

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

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

В SQL эти конструкции записываются без OR и AND, = и !=:

X IN (y1, y2, ..., yN)
X NOT IN (y1, y2, ..., yN)

X>[y1, y2, ..., yN] -> (X > MAX(y1, y2 ... yN))

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

Ошибка. MIN и MAX в SQL - агрегатные функции по столбцу, имеющие единственный аргумент. Для выбора минимального / максимального из нескольких перечисленных значений в SQL используются функции LEAST и GREATEST. Да и BETWEEN в SQL - совсем не функция.

Спасибо огромное за ваш комментарий, считаю, что с его появлением статья уже свою роль сыграла.
Действительно, с функциями MIN и MAX мой промах. В свое оправдание замечу, что настрой был и остается опираться на чистый SQL: OR, AND, NOT, =, >, <. Потому что применение нотации может оказаться неожиданным, в т.ч и в области, где операторы <= не определены. Этим и объясняется отсутствие IN, а также некоторое дублирование синтаксиса. А наличие-таки BETWEEN, MAX и MIN - это дань лени и спешке.
Что особенно любопытно, хотя и не неожиданно - DeepSeek ошибки с MAX пропустил.
Работать со временем... откровенно говоря, я об этом не думал, но подумаю обязательно.
В общем, спасибо вам еще раз.

А теперь вспомним про трехзначную логику и null

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

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

Все верно, но... это только первая итерация. В сущности - это тот же json, но безусловно элегантнее.
Смотрите. В действительности задачи данного проекта состоят в следующем:

  1. Сократить формат условных выражений SQL-подобного синтаксиса. Проще говоря, любого, или почти любого выражения WHERE.
    Очевидное, но не единственное, решение - конвертация из существующих объектных форматов или форматов передачи данных - json, xml, xsd, yml и т.д. и т.п.
    Альтернатива - собственный формат, что и реализовано в предложенном вами решении. Я же остановился на json.

  2. Сократить выбранный объектный формат до минимального за счет сокращения области определения. В данном случае формат json - он же вообще для всего. Предложенный вами формат sql.tree - это конкретная json-подобная реализация полного sql-запроса. Что, в сущности, и является тем самым сокращением области определения. Но... недостаточным.
    Потому что здесь речь идет о выражениях WHERE, как о самых проблемных в смысле компактности. А в вашем решении (как и в json) проблема компактности остается, просто из горизонтали переходит в вертикаль, транспонируется.

В любом случае, все это очень любопытно, позже я посмотрю повнимательнее.
Спасибо.

Да, для меня было немного удивительным, что нет простого решения этой проблемы

Пока нотация нелогична, на мой взгляд.

Х = [1,2] // определят операцию "или" или операцию equal_any.

В то время как другие, например

X < [1,2] // определяет операцию "и" или операцию more_than_all

Да и минус перед числом как "не" сильно сбивает с толку.

Признаю ваш аргументы убедительными, что касается и принятия - это вопрос...
Кстати, это и DeepSeek отметил - мол, не все понятно без документации.
Относительно минуса, как NOT. Да, переход от математического контекста к логическому несколько неожидан, особенно если игреки не числа, а строки, к примеру. Но это сделано в угоду компактности, и, полагаю, этот скилл быстро усвоится.

Что касается остального... Намекаете на то, что нет приведения к единой ДНФ, КНФ? Думаю над этим.

Если я понял, что такое "X = [1.2]", то я должен понять и что такое "х < [1.2]", а я не понимаю, потому что они действуют по-разному.

Компактность? Для чего? Экономите место в Git? Почему XML и потом JSON стали стандартном несмотря на свою длину и многословность? Потому что они сходу понятны без документации. Чем меньше чел будет привыкать, как вы написали, к нотации, тем лучше.

И тем не менее. Таков путь.
Компактность для того, чтобы не пришлось скроллить несколько сотен строк.

Это у вас один запрос на несколько сотен? Жёстко.

А про путь мандалорцам втирайте, а нам не надо. 😎

Кстати, в вашем развернутом вопросе о компактности содержится и ответ.
Почему json победил... ну не победил конечно, но здорово потеснил xml на большей части поля боя? Не в последнюю очередь потому, что:

"Какое-то_число": 777,

значительно компактнее, и более удобочитаемо, чем:

<Какое-то_число>777</Какое-то_число>

Да вы шо?

<rec
  Какое-то-число="666"
  Какой-то-текст="диаболо"
/>

napkin - препроцессор-оркестратор sql запросов на хаскел (используется на проде) работает с кучей бекэндов

Зарегистрируйтесь на Хабре, чтобы оставить комментарий

Публикации