Почему добавление круглых скобок в SQL-запрос приводит к изменению результатов?
Когда я выполняю следующий запрос, хотя есть 11 записей, которые соответствуют, ни один из них не возвращается как написанный. Однако, если я удаляю скобки в строках 6 и 9, все 11 записей возвращаются, как ожидалось.
1 select obj_id, obj_title, UI_DISPLAYNAME
2 from PITS_OBJECT
3 LEFT OUTER JOIN ui_displayname_view ON obj_create_ui_id = UI_ID
4 where
5 /* w/ parens, no results, w/o parens, expected results */
6 (
7 Upper( UI_DISPLAYNAME ) LIKE Upper( '%smith%' )
8 OR Upper( OBJ_TITLE ) LIKE Upper( '%smith%' )
9 )
10 /* end w/ parents, no results.... */
11 AND OBJ_ID IN (select obj_id from PITS_OBJECT where
12 (UPPER( OBJ_TITLE ) LIKE UPPER( '%smith%' ))
13 AND obj_id in( select sa_obj_id as obj_id from security_access
14 where sa_type_id = 494
15 and sa_usrgrp_id = 35
16 and sa_usrgrp_type_id = 230
17 union
18 select sa_obj_id from security_access
19 where sa_type_id = 494
20 and sa_usrgrp_type_id = 231
21 and sa_usrgrp_id in ( select ug_gi_id from user_group where ug_ui_id = 35)) )
Зачем это? Не означает ли утверждение OR, что одно или другое должно быть истинным? Что мне здесь не хватает?
Ответы
Ответ 1
Три слова: порядок операций. Как и в математике, некоторые операторы имеют приоритет над другими (например, умножение происходит до добавления), если вы не используете круглые скобки, чтобы заставить его по-своему. В этом случае AND
имеет более высокий приоритет, чем OR
.
Без добавления ваших собственных круглых скобок предложение WHERE
оценивается следующим образом:
Upper( UI_DISPLAYNAME ) LIKE Upper( '%smith%' )
OR
(Upper( OBJ_TITLE ) LIKE Upper( '%smith%' )
AND OBJ_ID IN (select obj_id from PITS_OBJECT where
...)
Но когда вы вручную добавляете эти скобки, вы сначала заставляете OR
оценивать.
(Upper( UI_DISPLAYNAME ) LIKE Upper( '%smith%' )
OR Upper( OBJ_TITLE ) LIKE Upper( '%smith%' ))
AND OBJ_ID IN (select obj_id from PITS_OBJECT where
...
Изменить: Я должен ответить на ваш вопрос о том, почему вы возвращаете больше данных. Причина в том, что без круглых скобок двигатель будет замыкать свою проверку, если обнаружит, что строка 7 истинна. Другими словами, он будет включать все записи, где Upper( UI_DISPLAYNAME ) LIKE Upper( '%smith%' )
, независимо от других критериев.
Когда вы добавляете в эти круглые скобки, логика изменяется. Он будет содержать записи, где Upper( UI_DISPLAYNAME ) LIKE Upper( '%smith%' ) OR Upper( OBJ_TITLE ) LIKE Upper( '%smith%' )
, а затем он проверяет, что запись ТАКЖЕ удовлетворяет внутреннему выбору, который начинается в строке 12. Эти дополнительные записи не отображаются, потому что они не соответствуют критериям этого внутреннего выбора.
Ответ 2
Ваше предложение where в настоящее время аналогично следующему:
(A || B) && C && D
Без круглых скобок это выглядит следующим образом
A || B && C && D
Что эквивалентно
A || (B && (C && D))
Ответ 3
Это связано с приоритетом операторов AND
и OR
. AND
имеет более высокий приоритет.
http://download.oracle.com/docs/cd/B19306_01/server.102/b14200/conditions001.htm#i1034834
Ответ 4
Поскольку вы изменили инструкцию where, чтобы всегда возвращать записи, где
Upper( OBJ_TITLE ) LIKE Upper( '%smith%' )
истинно, независимо от вашего следующего И
Ответ 5
Это основной порядок операций. Скобки означают, что все протестировано, прежде чем что-либо еще будет проверено. Затем значение, возвращаемое после оценки элементов в круглых скобках, будет использоваться для оценки остальной. Поскольку AND имеет приоритет над OR, скобки заставляют SQL сначала оценивать OR.