Почему добавление скобок в запросе SQL может привести к изменению результатов? - PullRequest
15 голосов
/ 17 ноября 2011

Когда я выполняю следующий запрос, даже при наличии 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)) )

Почему это имеет значение?Не означает ли утверждение ИЛИ, что одно или другое должно быть правдой?Что мне здесь не хватает?

Ответы [ 5 ]

14 голосов
/ 17 ноября 2011

Ваше предложение where в настоящее время аналогично следующему:

(A || B) && C && D

Без скобок это выглядит следующим образом

A || B && C && D

Что эквивалентно

A || (B && (C && D))
14 голосов
/ 17 ноября 2011

Три слова: порядок операций. Как вы узнали в математике, некоторые операторы имеют приоритет над другими (например, умножение происходит перед сложением), если вы не используете скобки, чтобы сделать это по-своему. В этом случае 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. Эти дополнительные записи не отображаются, поскольку они не соответствуют критериям этого внутреннего выбора.

1 голос
/ 17 ноября 2011

Это связано с приоритетом операторов AND и OR.AND имеет более высокий приоритет.http://download.oracle.com/docs/cd/B19306_01/server.102/b14200/conditions001.htm#i1034834

0 голосов
/ 17 ноября 2011

Это основной порядок операций.Скобки означают, что все проверяется прежде, чем что-либо еще проверяется.Значение, возвращаемое после оценки элементов в скобках, затем будет использовано для оценки остальных.Поскольку AND имеет приоритет над OR, скобки заставляют SQL сначала вычислять OR.

0 голосов
/ 17 ноября 2011

Поскольку вы изменили свой оператор where, чтобы всегда возвращать записи, где Upper( OBJ_TITLE ) LIKE Upper( '%smith%' ) равно true, независимо от вашего следующего AND

...