How to compare rows as lists in SQL? - sql

I have a many to many table which has 3 primary keys shown below :
table1 : key_1, key_2, key_3
I want to compare rows as lists,
For Example :
table1 would be :
key_1 key_2 key_3
row1: 10 | 100 | 150
row2: 10 | 101 | 150
row3: 10 | 103 | 151
row4: 11 | 100 | 150
row5: 11 | 101 | 150
row6: 11 | 103 | 151
So what I'd like to achive is to compare my table filtered by key_1 and find duplicate list of rows.
So in this scenerio,
SELECT * FROM table1 where key_1 = 10;
returns 3 rows (row1, row2, row3) and
SELECT * FROM table1 where key_1 = 11;
also returns 3 rows (row4, row5, row6)
And as you see above, first result of 3 rows has same key_2 & key_3
values with the second result of 3 rows.
So how can I query this, get rows as lists and compare them?
I know that this question looks something stupid but please, I'd very glad if you help me. Thanks in advance :)

You can search for unmatched rows of a full outer join.
For example the following query finds any difference between group 10 and 11:
select *
from table1 a
full join table1 b on a.key2 = b.key2 and a.key3 = b.key3
where a.key2 is null or b.key2 is null
and a.key1 = 10 and b.key1 = 11
If the query returns no rows, then the groups are identical.

If you wanted to find key_2 and key_3 pairs which repeat for the two values of key_1:
select key_2, key_3
from table1
where key_1 in (10, 11)
group by key_2, key_3
having count(1) > 1
To find the values of key_1 for which same key_2 and key_3 exist:
select distinct key_1
from table1
inner join (
select key_2, key_3
from table1
group by key_2, key_3
having count(1) > 1
) t (key_2, key_3)
on table1.key_2 = t.key_2
and table1.key_3 = t.key_3
The above query only tells key_1 value has at least one other key which has the same key_2 and key_3. It does not tell you what is the other key_1 value or what are the key_2 and key3. It seems to be what you were asking for but I am not sure if that is very useful.

Related

How to separate comma separate values and get aggregate of a column in SQL?

I have a table T1 as below
product_id val
123,567 5
999 4
999 3
and another table T2,
t_product_id // this maps to product_id in above table
123
999
In the final output, for t_product_id in table T2 I have to get value for it from T1. For duplicate product_ids (999) I want to get the min value, and for 123 I want to get 5
This is how output should look like
product_id value
123 5
999 3
My query ->
select t1.product_id, min(t1.value)
from T1 t1
group by t1.product_id
I am not sure what needs to be done next. How to separate comma separated values and check if 123 from T2 exists in T1 and get the value for it
it's not possible to keep only one product_id per row in table T1?
I think this would simplify matters for you. T1 would be:
123 | 5
567 | 5
999 | 4
999 | 3
Use join to only select the ids that exist in T2
select t1.product_id, min(t1.value)
from T1 t1 join T2 on (t1.product_id = t2.t_product_id)
group by t1.product_id

oracle sql to find the rows with one or more duplicate results in a same table

I have the below sample data set and I'm trying to come up with a query to find one or more duplicate rows from the same table
TABLE A: with 2 columns as below
CODE_NAME, RESULT
ABC 1
BBC 1
ZZZ 5
ZZZ 6
ZZZ 7
KBC 2
ZBC 2
CCC 2
XYZ 3
MNC 4
And my output should give all the unique rows with duplicate values in the result column such as below
CODE_NAME, RESULT
ABC 1
BBC 1
KBC 2
ZBC 2
CCC 2
i tried below but its not giving me correct result
select A t1, A t2
where A.result = b.result
and a.code_name <> b.code_name
Appreciate other suggestions.
You can use exists:
select t.*
from t
where exists (select 1
from t t2
where t2.result = t.result and t2.code_name <> t.code_name
);
For performance on a large dataset, you want an index on (result, code_name).
You might find it more convenient to have one row per duplicated result:
select result,
listagg(code_name, ',') within group (order by code_name)
from t
group by result
having count(*) > 1;

SQL (oracle) Update some records in table using values in another table

I have to tables :
Table1
--------------------------------
ID VAL1 DATE1
--------------------------------
1 1 20/03/2015
2 null null
3 1 10/01/2015
4 0 12/02/2015
5 null null
Table2
--------------------------------
ID VAL2 DATE1
--------------------------------
1 N 02/06/2015
1 N 01/08/2015
2 null null
3 O 05/04/2016
3 O 02/02/2015
4 O 01/07/2015
5 O 03/02/2015
5 N 10/01/2014
5 O 12/04/2015
I want to update :
column VAL1 (of Table1) with '0', if VAL2 (of Table2) is equal to 'O'
column DATE1 (of Table1) with the earliest DATE2 (of Table2) for each ID (here my problem)
(This two tables are not so simple, it's just for illustration, they can be joined with the ID column).
Here my code :
UPDATE Table1 t1
SET t1.VAL1 = '0',
t1.DATE1 = (select min(t2.DATE2) --To take the first DATE for each ID where VAL2='O' (not working fine)
FROM Table2 t2, Table1 t1
WHERE trim(t2.ID) = trim(t1.ID)
AND VAL2='O')
WHERE EXISTS (SELECT NULL
FROM Table2 t2
WHERE trim(t2.ID) = trim(t1.ID)
AND t2.Table2 = 'O')
AND VAL1<>'0'; --(for doing the update only if VAL1 not already equal to 0)
The expected result is :
Table1
--------------------------------
ID VAL1 DATE1
--------------------------------
1 1 20/03/2015
2 null null
3 0 02/02/2015
4 0 01/07/2015
5 0 10/01/2014
The result I get is :
Table1
--------------------------------
ID VAL1 DATE1
--------------------------------
1 1 20/03/2015
2 null null
3 0 10/01/2014
4 0 10/01/2014
5 0 10/01/2014
My problem is that the DATE1 is always updated with the same date, regardless of the ID.
You shouldn't have a second reference to table1 in the first subquery; that is losing the correlation between the subquery and the outer query. If you run the subquery on its own it will always find the lowest date in table2 for any ID that has val2='O' in table1, which is 10/01/2014. (Except your sample data isn't consistent; that's actually N so won't be considered - your current and expected results don't match the data you showed, but you said it isn't real). Every row eligible to be updated runs that same subquery and gets that same value.
You need to maintain the correlation between the outer query and the subquery, so the subquery should use the outer table1 for its join, just like the second subquery already does:
UPDATE Table1 t1
SET t1.VAL1 = '0',
t1.DATE1 = (select min(t2.DATE2)
FROM Table2 t2
WHERE trim(t2.ID) = trim(t1.ID)
AND VAL2='O')
WHERE EXISTS (SELECT NULL
FROM Table2 t2
WHERE trim(t2.ID) = trim(t1.ID)
AND t2.Val2 = 'O')
AND VAL1<>'0';
You can use this UPDATE statement.
UPDATE TABLE1 T1
SET T1.VAL1 = '0',
T1.DATE1 = (SELECT MIN(T2.DATE2)
FROM TABLE2 T2
WHERE TRIM(T2.ID) = TRIM(T1.ID)
AND T2.VAL2='O')
WHERE T1.ID IN (SELECT T2.ID FROM TABLE2 T2 WHERE T2.VAL2='O')
Hope it will help you.
MYSQL Solution
Hope this MySql syntax also works with ORACLE.
The issue with the SQL is that it only consider the records with VAL2=='O' when calculating the earliest date. So the last record have the date as shown in table below. Record "5 N 10/01/2014" is not considered.
UPDATE Table1, (SELECT * FROM (SELECT * FROM table2 WHERE VAL2='O' ORDER BY ID, DATE1) X GROUP BY X.ID) T2
SET Table1.DATE1=T2.DATE1, Table1.VAL1=0
WHERE Table1.ID=T2.ID
..
Table1
--------------------------------
ID VAL1 DATE1
--------------------------------
1 1 20/03/2015
2 null null
3 0 02/02/2015
4 0 01/07/2015
5 0 **03/02/2015**
Tested on MySql 5.6.14

SQL: All rows of two tables merged together

I am trying to combine two different tables in a select statement where all the rows in the first table are matched with all the rows in the second table. For example:
Table1
Table1_ID | FKey_Table2_ID
1 9
2 null
Table2
Table2_ID | Table2_Value
9 Yes
10 No
11 Maybe
Results needed:
Table1_ID | FKey_Table2_ID | Table2_ID | Table2_Value
1 9 9 Yes
1 null 10 No
1 null 11 Maybe
2 null 9 Yes
2 null 10 No
2 null 11 Maybe
Please note that the first row in Table1 has a key already assigned from Table2.
This is called a cross join and can be accomplished like this:
SELECT Table1_ID, FKey_Table2_ID, Table2_ID, Table2_Value
FROM Table1
CROSS JOIN Table2
Or more simply
SELECT Table1_ID, FKey_Table2_ID, Table2_ID, Table2_Value
FROM Table1, Table2
SELECT * FROM Table1
CROSS JOIN
Table2

Selecting distinct rows based on column

A particular query of mine results data this way.
Id Size
123 1
123 1
123 2
123 2
134 1
134 1
134 2
I want the results get me the count eliminating the duplicate size like
Id Size
123 1
123 2
134 1
134 2
Above was result of joining two tables. Problem is I cant use distinct in this case.
Here is how tables are
Table1:
Id Created ... .. .. ..
123 date1 ....
134 date2 ....
Table2:
Id Size
123 1
123 2
134 1
134 2
I have my query that select from Table1 based on CreatedDate, its like this
select count(*)
from table1
join table2
on table1.id = table2.id
where table1.creates between '' and ''.
How do you get the distinct sizes.
If I use select count(distinct table2.size), it only returns 1 and 2 for all rows.
SELECT DISTINCT Id, Size
FROM table1
This should give you a list of distinct Id and Size combinations.
select count(distinct table1.id, table2.size)
from table1
join table2
on table1.id = table2.id
where table1.creates between '' and ''
see it working live in an sqlfiddle
Sometimes the solution is so obvious... :)
UPDATE: another way
select count(*) from (
select distinct table1.id, table2.size
from table1
join table2
on table1.id = table2.id
where table1.creates between '' and ''
) sq