ПРОБЛЕМА
У меня такой запрос:
select a.id from a join b on ( a.id = b.my_a ) join ....
where
( /* complex and expensive conditional */ )
AND
(( /* conditional #1 */ )
OR ( /* conditional #2 */ )
OR ( /* conditional #3 */))
Я бы хотел, чтобы запрос возвращал что-то вроде:
select a.id, conditional_1_eval_value, conditional_2_eval_value, conditional_3_eval_value from a join b on ( a.id = b.my_a ) join ....
where
( /* complex and expensive conditional */ )
AND
(( /* conditional #1 */ )
OR ( /* conditional #2 */ )
OR ( /* conditional #3 */))
, где conditional_1_eval_value
, conditional_2_eval_value
и conditional_3_eval_value
установлены в TRUE, FALSE, NULL. NULL означает, что условие не было оценено.
Таким образом, набор результатов может быть:
1, FALSE, NULL, TRUE ( condition_1, condition_3 were evaluate, condition_2 was not)
2, NULL, TRUE, TRUE ( condition_2, condition_3 were evaluate, condition_1 was not)
3, TRUE, FALSE, FALSE (all were evaluated)
condition_1
, condition_2
, condition_3
сами по себе сложны и включают коррелированные подзапросы и группировку.
EDIT:
Чего я пытаюсь достичь?
Нам нужно записать, какое условие вызвало возвращение строки. Нам не нужно знать все причины, по которым строка была возвращена. Таким образом, во второй строке примера результатов достаточно знать, что conditional_2
и conditional_3
оба были истинными. Незнание значения conditional_1
не имеет значения.
Достаточно знать, что по крайней мере одно условие было выполнено и что это было за условие.
Неоптимальные решения
Очевидно, я мог бы сделать это с UNION следующим образом:
select a.id, TRUE, NULL, NULL from a join b on ( a.id = b.my_a ) join ....
where
( /* complex and expensive conditional */ )
AND
( /* conditional #1 */ )
UNION
select a.id, NULL, TRUE, NULL from a join b on ( a.id = b.my_a ) join ....
where
( /* complex and expensive conditional */ )
AND
( /* conditional #2 */ )
UNION
select a.id, NULL, NULL, TRUE from a join b on ( a.id = b.my_a ) join ....
where
( /* complex and expensive conditional */ )
AND
( /* conditional #3 */)
Но это будет означать, что:
- общий «сложный и дорогой условный» оценивается 3 раза.
- что все условные выражения оцениваются, даже если другое условное условие уже удовлетворяло OR.
- был бы кошмар обслуживания, гарантирующий, что 3 копии общего сложного запроса идентичны (это можно решить, создав SQL в коде и скопировав общую строку - но это означает, что я нарушу другой внутренний стандарт всех SQL, не будучи встроенный в Java, но находящийся в XML-файле, видимом для DBA)
Использование CASE в select , которое дублирует каждое условие с 1 по 3, позволяет избежать оценки общего условия 3 раза. Однако сложность условия 1-3 такова, что это может оказаться невозможным.
Использование select в предложении FROM будет неудобным и невозможным, поскольку FROM SELECT не может быть коррелированным запросом. Я не уверен, что смогу создать полезный некоррелированный запрос.
Хранимые процедуры будут работать. Однако это будет первая такая хранимая процедура и значительно увеличит сложность нашего развертывания.
Выполнение оценки conditional_1
, conditional_2
, conditional_3
в Java-коде. Это то, что мы сейчас делаем, и оно запускается sloooooooow. Много данных, передаваемых, когда база данных предназначена для фильтрации набора результатов - не следует делать это в Java!
Предложения по решению?
Любой
Я должен также добавить, что приветствую ответы, в которых говорится, что эта проблема не может быть решена. Знание того, что проблема не может быть решена, сэкономило бы мне время, пытаясь решить ее с использованием исключительно SQL.
Если бы мне пришлось выбирать, я бы склонялся к тому, чтобы узнать, как будет выглядеть хранимая процедура mysql.
Так что, если вы хотите добровольно предложить, как будет выглядеть хранимая процедура mysql, это было бы замечательно.