简体   繁体   中英

Oracle - Find matched records with a different value for one field

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

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.

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.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM