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

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.

Related

how to extract the rows where a group appears more than a certain number of times

I have the following table
col1 col2 col3 key
A B C 1
A B B 2
A B B 3
A B D 4
B D C 5
I would like to extract the rows where the group col1, col2, col3 appears more than once in the table.
A B B 2
A B B 3
So far, I have:
SELECT col1, col2, col3, count(*)
FROM db.table
GROUP BY col1, col2, col3
HAVING count(*) > 1
col1 col2 col3 count(*)
A B B 2
Is there a way to extract those rows with A B B without having to join the final table with the initial table?
You could use exists logic:
SELECT col1, col2, col3, "key"
FROM yourTable t1
WHERE EXISTS (SELECT 1 FROM yourTable t2
WHERE t2.col1 = t1.col1 AND t2.col2 = t1.col2 AND
t2.col3 = t1.col3 AND
t2."key" <> t1."key");
Try below query with CTE
with MyCTE
as
(
select col1,col2,col3,Key,COUNT(*) over(PARTITION BY col1,col2,col3 order
by col1,col2,col3) as Duplicate from yourtable
)
select col1,col2,col3,key from MyCTE where Duplicate>1

SQL join two tables that have the same columns, with an overlapping `id` column, but merge based on if table1.col1 >= table2.col1

I want to join two tables that have the same columns, with an overlapping id column, but merge based on if table1.col1 >= table2.col1. This is in SQL.
If table1.col1>=table2.col1, use the columns from table1.
If table1.col1< table2.col1, then use columns from table2.
If the id does not exist in table1 but exists in table2, use the columns from table2
If the id does not exist in table2 but exists in table1, use the columns from table1
For example:
Table1:
id
col1
col2
col3
A
3
5
4
B
1
2
3
C
8
9
7
Table2:
id
col1
col2
col3
A
2
5
6
B
5
7
8
D
2
3
4
I want the result to be:
id
col1
col2
col3
A
3
5
4
B
5
7
8
C
8
9
7
D
2
3
4
I have tried union, full outer join, and CASE statements, but am stuck
I think individual case expressions for each column might be best:
select id,
(case when t1.col1 < t2.col1 then t2.col1 else t1.col1 end) as col1,
(case when t1.col1 < t2.col1 then t2.col2 else t1.col2 end) as col2,
(case when t1.col1 < t2.col1 then t2.col3 else t1.col3 end) as col3
from t1 full join
t2
using (id);
If that is cumbersome, another approach uses not exists:
select t1.*
from t1
where not exists (select 1
from t2
where t2.id = t1.id and t2.col1 > t1.col1
)
union all
select t2.*
from t2
where not exists (select 1
from t1
where t2.id = t1.id and t1.col1 >= t2.col1
);
Another solution:
SELECT DISTINCT ON (id) *
FROM (
SELECT *
FROM table1
UNION ALL
SELECT *
FROM table2
) AS aux
ORDER BY id, col1 DESC;
I tried it in Postgresql.

Compare values in Different column and row

I have the following table:
ID COl1 COl2
1 13 15
2 13 16
3 13 17
4 17 13
What I need is to select all rows where Col1 value is available in Col2 and vice versa.
This case only ROW 4 or ROW 3 should be returned. They have same values (13 17).
Take it as col1 is Buyer and col2 is Seller
I want to know who are the users who bought / sell from EACH OTHER.
if user a bought from user b, user b should buy from user a in order to be returned.
SELECT
a.*
FROM
yourTable a
INNER JOIN
yourTable b
ON a.Col1 = b.Col2
AND a.Col2 = b.Col1
AND a.id != b.id
This can be done by using sub queries:
SELECT ID, COl1, COl2
FROM table1 WHERE COl1 IN (SELECT DISTINCT COl2 FROM table1)
UNION
SELECT ID, COl1, COl2
FROM table1 WHERE COl2 IN (SELECT DISTINCT COl1 FROM table1)
This sounds like exists:
select t.*
from t
where exists (select 1 from t t2 where t2.col1 = t.col2) and
exists (select 1 from t t2 where t2.col2 = t.col1) ;
If you want them in the same row, I would still use exists:
select t.*
from t
where exists (select 1 from t t2 where t2.col1 = t.col2 AND t2.col2 = t.col1) ;
I recommend this over a self-join because it will not generate multiple rows if there are multiple examples of the buyers and sellers on either side.
This also works
SELECT * FROM your_table WHERE
col1 IN (SELECT col2 FROM your_table)
AND
col2 IN (SELECT col1 FROM your_table);

Select Group data with one matching condition

Table:
Col1 Col2
1 2
1 3
1 4
2 2
2 3
first need to check all rows with col2 = 4
Then need to select all rows with values col1
The result should be:
1 2
1 3
1 4
Off the top of my head
SELECT A.* FROM MyTable A JOIN MyTable B ON A.Col1 = B.Col1 WHERE B.Col2 = 4
I think you want this:
select t.*
from t
where t.col1 in (select t2.col1 from t t2 where t2.col2 = 4);
This query checks on both columns, where col2 = 4 and col1 = 1, from what i can understand in your description.
SELECT t1.col1, t2.col2 FROM Table t1
WHERE t1.col2 = 4
UNION
SELECT t2.col1, t2.col2 FROM Table t2
WHERE t2.col1 = 1

Combine multiple tables in one

If I have tlb1 as :
col1
1
2
3
Now I have tlb2 as:
col2 col3
4 Four
5 Five
6 SIX
No I have tlb3 as
col4 col5
sample14 sample15
sample24 sample25
sample34 sample35
What can be the query if I want result as :
col1 col2 col3 col4 col5
1 4 Four sample14 sample15
2 5 Five sample24 sample25
3 6 Six sample34 sample35
I tried with :
select ( (select * from tlb1), (select * from tlb2),(select * from tlb3)) T
But this failed.
Please help me.
with t1 as (select col1, row_number() over (order by col1) rn from tbl1 ),
t2 as (select col2,col3, row_number() over (order by col2) rn from tbl2),
t3 as ( select col4,col5, row_number() over (order by col4) rn from tbl3)
select t1.col1,t2.col2,t2.col3,t3.col4,t3.col5
from t1 full outer join t2 on t1.rn = t2.rn
t3 full outerjoin t2 on t2.rn = t3.rn
try something like this...