Reputation: 35343
I was assisting with:
Consider the following trying to find all records found in one set but not the other. (note the --x below denotes records expected in result set)
Oracle Database 11g Enterprise Edition Release 11.2.0.4.0 - 64bit
With test1 (A,b,c) as (
SELECT 2001, 'abc', 'john' from dual union all--
SELECT 2008, 'cab', 'sam' from dual union all--x
SELECT 2002, 'qwe', 'mike' from dual union all--x
SELECT 2002, 'asd', 'samuel' from dual union all--
SELECT 2012, 'ddd', 'sammy' from dual),--x
test2 (a,b,c) as (
SELECT 2001, 'abc', 'john' from dual union all--
SELECT 2008, 'c@b', 'saam' from dual union all--x
SELECT 2009, 'qwe', 'mike' from dual union all--x
SELECT 2002, 'asd', 'samuel' from dual union all--
SELECT 2001, 'a bc', 'john' from dual ),--x
cte as (Select * from test1 minus Select * from test2),
cte2 as (Select * from test2 minus Select * from test1)
Select * from cte
union
Select * from cte2;
which results in expected results:
+------+------+-------+
| A | B | C |
+------+------+-------+
| 2001 | a bc | john |
| 2002 | qwe | mike |
| 2008 | c@b | saam |
| 2008 | cab | sam |
| 2009 | qwe | mike |
| 2012 | ddd | sammy |
+------+------+-------+
VS... (why do we need to use a CTE? can't we just union all the two queries?)
With test1 (A,b,c) as (
SELECT 2001, 'abc', 'john' from dual union all
SELECT 2008, 'cab', 'sam' from dual union all
SELECT 2002, 'qwe', 'mike' from dual union all
SELECT 2002, 'asd', 'samuel' from dual union all
SELECT 2012, 'ddd', 'sammy' from dual),
test2 (a,b,c) as (
SELECT 2001, 'abc', 'john' from dual union all
SELECT 2008, 'c@b', 'saam' from dual union all
SELECT 2009, 'qwe', 'mike' from dual union all
SELECT 2002, 'asd', 'samuel' from dual union all
SELECT 2001, 'a bc', 'john' from dual )
Select * from test1 minus select * from test2
union ALL
Select * from test2 minus select * from test1
Which just gives us.
+------+------+------+
| A | B | C |
+------+------+------+
| 2001 | a bc | john |
| 2008 | c@b | saam |
| 2009 | qwe | mike |
+------+------+------+
Apparently not... Why? (comments indicate if I wrap each select in () for the minus it works (and it does) having to do with equal precedence in operation.) So this works:
(Select * from test1 minus select * from test2)
union ALL
(Select * from test2 minus select * from test1)
I know I could union both sets after distinct and then do a having count... but why did the union of the inverse minused sets not work? Is it a bug (or a feature that I can't find doc on? :P) [Answered in comments!] waiting for an answer to accept!
SELECT *
FROM (SELECT Distinct * FROM test1 UNION ALL
SELECT Distinct * FROM test2)
GROUP BY A,B,C
HAVING count(*) = 1
So... what my query was doing was:
[ANSWER FROM COMMENTS waiting for someone to post!]
(Select * from test1 minus select * from test2 UNION ALL SELECT * FROM TEST2)
MINUS select * from test1
instead of
(Select * from test1 minus select * from test2)
UNION ALL
(SELECT * FROM TEST2 MINUS select * from test1)
Upvotes: 4
Views: 3989
Reputation: 49270
Select * from cte
union
Select * from cte2
The cte
s being union
ed here evaluate minus
operation on the 2 tables individually.
However, this query
Select * from test1 minus select * from test2
union ALL
Select * from test2 minus select * from test1
has minus
and union
which are set operators. All set operators have equal precedence. Hence they get evaluated one-by-one from left
to right
.
Hence the results of these queries are different. To explicitly specify the order, use parentheses around the two queries.
(Select * from test1 minus select * from test2)
union
(Select * from test2 minus select * from test1)
Documentation on set operators
Upvotes: 3