Why would the addition of parentheses in SQL query cause the results to change?

Sam F. picture Sam F. · Nov 17, 2011 · Viewed 27.5k times · Source

When I execute the following query, even though there are 11 records that match, none are returned as written. However, if I remove the parentheses on lines 6 and 9, all 11 records are returned as expected.

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)) )

Why would this matter? Wouldn't the OR statement mean that one or the other must be true? What am I missing here?

Answer

ean5533 picture ean5533 · Nov 17, 2011

Three words: order of operations. It's like you learned in math, certain operators take precedence over others (like multiplying comes before adding) unless you use parentheses to force it your way. In this case, AND has a higher precedence than OR.

Without adding in your own parentheses, your WHERE clause gets evaluated like this:

Upper( UI_DISPLAYNAME ) LIKE Upper( '%smith%' )
OR 
(Upper( OBJ_TITLE ) LIKE Upper( '%smith%' ) 
    AND OBJ_ID IN (select obj_id from PITS_OBJECT where 
    ...)

But when you manually add in those parentheses, you're forcing the OR to be evaluated first.

(Upper( UI_DISPLAYNAME ) LIKE Upper( '%smith%' )
    OR Upper( OBJ_TITLE ) LIKE Upper( '%smith%' ))
AND OBJ_ID IN (select obj_id from PITS_OBJECT where 
...

Edit: I should directly answer your question about why you're getting back more data. The reason is because, without the parentheses, the engine will short-circuit its check if it finds that line 7 is true. In other words, it will include all records where Upper( UI_DISPLAYNAME ) LIKE Upper( '%smith%' ), regardless of the other criteria.

When you add in those parentheses, the logic changes. It will include records where Upper( UI_DISPLAYNAME ) LIKE Upper( '%smith%' ) OR Upper( OBJ_TITLE ) LIKE Upper( '%smith%' ), and then it checks that the record ALSO satisfies the inner select that starts on line 12. Those extra records don't show up because they're not meeting the criteria of that inner select.