Reputation: 19574
Suppose I have the following table in my Oracle DB:
Col1: Col2: ... Coln:
1 a ... 1
1 a ... 1
1 b ... 1
1 b ... 1
1 c ... 1
1 a ... 1
2 d ... 1
2 d ... 1
2 d ... 1
3 e ... 1
3 f ... 1
3 e ... 1
3 e ... 1
4 g ... 1
4 g ... 1
And, what I want to get is a distinct list of records where, for Col1
, Col2
is different - Ignoring any times that Col2
matches for all of Col1
.
So, in this example I would like to get the result set:
Col1: Col2:
1 a
1 b
1 c
3 e
3 f
Now, I figured out how to do this using a query that feels fairly complex for the question at hand:
With MyData as
(
SELECT b.Col1, b.Col2, count(b.Col2) over(Partition By b.Col1) as cnt from
(
Select distinct a.Col1, a.Col2 from MyTable a
) b
)
select Col1, Col2
from MyData
where cnt > 1
order by Col1
What I'm wondering is what is a nicer way to do this - I didn't manage to do this using GROUP BY
& HAVING
and probably think this could maybe be done using a self-join... This is more of a quetion to see / learn new ways to get a result in a nicer (and perhaps more efficient) query.
Thanks!!!
Upvotes: 0
Views: 2585
Reputation: 36127
Try this query:
SELECT distinct *
FROM table1 t1
WHERE EXISTS
( SELECT 1 FROM table1 t2
WHERE t1.col2 <> t2.col2
AND t1.col1 = t2.col1
)
order by 1,2
demo: http://www.sqlfiddle.com/#!4/9ce10/12
----- EDIT -------
Yes, there are other ways to do this:
SELECT distinct col1, col2
FROM table1 t1
WHERE col2 <> ANY (
SELECT col2 FROM table1 t2
WHERE t1.col1 = t2.col1
)
order by 1,2;
SELECT distinct col1, col2
FROM table1 t1
WHERE NOT col2 = ALL (
SELECT col2 FROM table1 t2
WHERE t1.col1 = t2.col1
)
order by 1,2
;
SELECT distinct t1.col1, t1.col2
FROM table1 t1
JOIN table1 t2
ON t1.col1 = t2.col1 AND t1.col2 <> t2.col2
order by 1, 2
;
SELECT t1.col1, t1.col2
FROM table1 t1
JOIN table1 t2
ON t1.col1 = t2.col1
GROUP BY t1.col1, t1.col2
HAVING COUNT( distinct t2.col2 ) > 1
order by 1, 2
;
SELECT t1.col1, t1.col2
FROM
table1 t1
JOIN (
SELECT col1
FROM table1
GROUP BY col1
HAVING COUNT( distinct col2 ) > 1
) t2
ON t1.col1 = t2.col1
GROUP BY t1.col1, t1.col2
ORDER BY t1.col1, t1.col2
;
Demo --> http://www.sqlfiddle.com/#!4/9ce10/33
Try them all, I really don't know how they will perform on your data.
However, creating a composite index:
CREATE INDEX name ON table1( col1, col2 )
will most likely speed up all of these queries.
Upvotes: 3
Reputation: 1270653
Here is a method that uses aggregation and an analytic function:
with t as (
select col1, col2,
count(*) over (partition by col1) as cnt
from table1
group by col1, col2
)
select col1, col2
from t
where cnt > 1;
What I would like to do is:
select col1, col2,
count(*) over (partition by col1) as cnt
from table1
group by col1, col2
having count(*) over (partition by col1) > 1;
However, this is not valid SQL because the analytic functions are not allowed in the having
clause.
Upvotes: 1