How to remove common records found in 2 tables? - mysql

For example:
table 1
x y
2 3
1 2
8 9
table 2
x y
2 3
8 9
So here I need to remove the common field found in both the table
result should be
Result
x y
1 2
only i should get a unique row

You can use NOT EXISTS :
SELECT t1.*
FROM table1 t1
WHERE NOT EXISTS (SELECT 1 FROM table2 t2 WHERE t2.X = t1.X AND t2.Y = t1.Y);

You can also use NOT EXISTS operator which is more efficient as it also considers NULL values while comparison.
select * from table1 A
where not exists (select name from table2 B where A.name=B.name)

Try this:
Demo 1
Demo 2
select x, y
from
(
select x, y
from table1
union all
select x, y
from table2
) i
group by x, y
having count(*) = 1

Assuming the task is "delete duplicated record from BOTH TABLES accounting NULLs":
DELETE t1.*, t2.*
FROM table1 t1
JOIN table2 t2 ON t1.x <=> t2.x
AND t1.y <=> t2.y;
fiddle
Assuming the task is "delete duplicated record from both tables NOT accounting NULLs":
DELETE t1.*, t2.*
FROM table1 t1
JOIN table2 t2 USING (x, y);
fiddle
If the task is "delete duplicated record from one table and store them in another table" then edit DELETE t1.*, t2.* and store only those table which records must be deleted, for example, DELETE t1.*.

Assuming this is to remove duplicate from a table that exist in another table
if all colums have non null value then:-
DELETE t1
FROM tbl_test_1 t1
INNER JOIN tbl_test_2 t2
ON t1.col_1 = t2.col_1
AND t1.col_2 = t2.col_2
WHERE t2.id is not null
Here if a particualr coulm from both table are NULL , we miss that.
So to catch colm match with NULL as well, try this:-
#to check before deletion
SELECT * ,
concat_ws("_",COALESCE(t1.col_1, 'null'),COALESCE(t1.col_2, 'null')),
concat_ws("_",COALESCE(t2.col_1,'null'),COALESCE(t2.col_2,'null'))
FROM tbl_test_1 t1
left JOIN tbl_test_2 t2
ON concat_ws("_",COALESCE(t1.col_1, 'null'),COALESCE(t1.col_2, 'null'))= concat_ws("_",COALESCE(t2.col_1, 'null'),COALESCE(t2.col_2, 'null'))
WHERE t2.id is not null
delete query
#delete query
DELETE t1
FROM tbl_test_1 t1
left JOIN tbl_test_2 t2
ON concat_ws("_",COALESCE(t1.col_1, 'null'),COALESCE(t1.col2, 'null'))= concat_ws("_",COALESCE(t2.col_1, 'null'),COALESCE(t2.col2, 'null'))
WHERE t2.id is not null

Related

How to get unique (not vice-versa) fields on MySQL

The title may be misleading but i don't know how to formulate it better.
Suppose i have these rows on my MySQL table:
table1:
id column1 column2
1 1 2
2 1 3
3 2 1
4 3 4
I have written a query to retrieve data that have similar vice-versa values on columns column1 and column2 (id: 1 & id: 3), but I'm having trouble querying over data that don't have similar vice-versa rows (id: 2 & id: 4) or that are sort of unique.
EDIT: The query i've used to get vice-versa rows
SELECT * FROM table1 t1
INNER JOIN table1 t2
ON (t1.column1 = t2.column2 AND t1.column2 = t2.column1);
You could use exists logic here:
SELECT id, column1, column2
FROM yourTable t1
WHERE NOT EXISTS (SELECT 1 FROM yourTable t2
WHERE LEAST(t2.column1, t2.column2) = LEAST(t1.column1, t1.column2) AND
GREATEST(t2.column1, t2.column2) = GREATEST(t1.column1, t1.column2));
A simple solution would be to use your query in the WHERE clause to filter out similar rows:
SELECT *
FROM table1 t1
WHERE (column1, column2) NOT IN
(SELECT t1.column1, t1.column2
FROM table1 t1
INNER JOIN table1 t2
ON t1.column1 = t2.column2 AND t1.column2 = t2.column1)
Demo here

get data from two tables fetching only one row from second table

i have two tables
t1:
sno val
12 A
13 B
14 C
t2:
refid val2
13 ba
13 bb
13 bc
using the following query:
select * from t1,t2 where t1.sno=t2.refid order by t2.refid;
and the query
select * from t1 join t2 on t2.refid = ( select refid from t2 where t1.sno = t2.refid limit 1 )
I get
B ba
B bb
B bc
and so on for all the possible combinations.
I want to get only first combination instead of all three like
B ba
C ca
and so on...
I mean, I just want only first row for every three combination that I am getting as a result of join.
As per my knowledge, I suggest below two ways to get your required output:
Way1 :
Use nested query to group by records then do join
select * from t1 a join (select * from t2 group by refid) b on a.sno= b.refid
way2:
But it's better to add auto increment key for tables like t2. Once you added auto increment key that will be useful in most use cases.
First add auto increment key to your table t2 by using below command
ALTER TABLE t2 add column id int(11) key auto_increment first;
Then execute the below join query:
select * from t1 a join (select *from t2 where t2.id in(select min(id) from t2 group by refid)) b on a.sno= b.refid
select t1.val,temp.refid from t1,(select t2.refid as refid, min(t2.val2) as val2 /*Assuming "first" row criteria*/ from t2 group by t2.refid) temp where t1.sno=temp.refid order by t2.sno;
Eliminated duplicates from t2 using sub-query and joined with t1.
If you want only one value and one column from the second table, a correlated subquery is an easy solution:
select t1.*,
(select t2.val2
from t2
where t1.sno = t2.refid
order by ? -- whatever defines "first"
limit 1
) as val2
from t1
order by t1.sno;
If you only want rows where there is a match, MySQL has a nice extension for having that fits the bill:
select t1.*,
(select t2.val2
from t2
where t1.sno = t2.refid
order by ?-- whatever defines "first"
limit 1
) as val2
from t1
having val2 is not null
order by t1.sno;
select * from (select ROW_NUMBER() OVER (PARTITION BY sno ORDER BY val2 ) AS rn, * from [dbo].[t1] a
join [dbo].[t2] b on a.sno = b.refid
) t
where rn = 1

Form a query to get the difference in two tables with a common column

I have two tables.One with original data (t1) and the other with altered data after some operation is performed (t2). The structure of the two tables is same (Columns - GUID, ID, Value). GUID, ID form the Primary Key.
GUID and ID will remain same after the operation. However, some IDs (in t1) may be absent in t2 and some may be added in t2.
Sample -
t1 t2
GUID ID Value GUID ID Value
(i) 1 a x 1 a x --> same
(ii) 1 b y 1 b w --> VALUE different
(iii) 2 a x --> extra ID in t1
(iv) 2 b z --> extra ID in t2
My goal is to print the difference in t1 and t2 in the following format (new table)
Difference
GUID ID Value1 Value2
(ii) 1 b y w --> VALUE different
(iii) 2 a x NULL --> extra ID in t1
(iv) 2 b NULL z --> extra ID in t2
My try -
I have split the problem into 3 parts.
Insert rows whose values are different
INSERT INTO Difference(GUID,ID,Value1,Value2)
SELECT t1.GUID, t1.ID, t1.Value, t2.Value from t1, t2
WHERE t1.GUID = t2.GUID and t1.ID = t2.ID and t1.Value != t2.Value
The above query returns correct values.
Insert rows with IDs present in t1 and not present in t2.
I want to use a query like this ->
INSERT INTO Difference(GUID,ID,Value1)
(SELECT t1.GUID, t1.ID, t1.Value from t1, t2
WHERE t1.GUID= t2.GUID and t1.ID IN
((SELECT GUID,ID FROM t1 ) EXCEPT
(SELECT GUID,ID FROM t2 ))) // I get an error here.
Error :- Only one expression can be specified in the select list when the subquery is not introduced with EXISTS.
I know I should select only "ID" column for IN clause. But that doesn't satisfy the condition. I want to use both GUID and ID in the 'IN' clause. I tried a number of other queries that didn't work. What should I do to get this result?
Same as 2nd with tables reversed.
you can union t1 joining t2 and t2 joining t1 and group by two columns key to allow only one record from their intersection
SELECT
x.GUID,
x.ID,
x.Value1,
x.Value2
FROM (
SELECT t1.GUID, t1.ID, t1.Value AS Value1, t2.Value AS Value2 FROM t1 LEFT JOIN t2 ON t2.GUID = t1.GUID AND t2.ID = t1.ID
UNION ALL
SELECT t2.GUID, t2.ID, t1.Value AS Value1, t2.Value AS Value2 FROM t2 LEFT JOIN t1 ON t1.GUID = t2.GUID AND t1.ID = t2.ID
) x
GROUP BY x.GUID, x.ID;

Conditional SELECT SQL with relational tables

Say I have an id in table1 which is a foreign key in table2 and there is a column in table2 called condition.
I need to select all ids from table 1 that aren't in table2 where condition = 1.
So for id in table 1 "select it" if it is not in table2 where condition = 1.
Edit: I used Ahsan Habib's answer and it worked great!
if you just want to select ID column from table1 this will work fine....Its just a simple set operation
select id from t1
minus
select id from t2 where condition = 1;
for all column you may try
select * from t1 whare id not in (select id from t2 where condition = 1);
This is almost a direct translation of what you are asking for:
select t1.*
from table1 t1
where t1.id not in (select t2.id from table2 t2 where t2.condition = 1);
Another way using NOT EXISTS
select t1.*
from table1 t1
where NOT EXISTS(select 1 from table2 t2 where t1.id = t2.id and t2.condition = 1);

joining tables with where clause

I am having two tables, the structure is given below
Table 1
schid
name
cost
type
Table 2
schid
details
oldcost
I am unable to write a query to display records from table 2 of let suppose type A OR B (Here as you can see type field is in table 1), Here one more thing to add is that schid is not a primary key, The query which i am executing is retrieving more records than expected, I think due to join, Can i execute it without using join
SELECT *
FROM Table1
JOIN Table2 ON Table1.schid=Table2.schid
WHERE Table1.type='A'
OR Table1.type='B'
This would help:
SELECT t2.schid, t2.details, t2.oldcost
FROM Table2 t2
JOIN Table1 t1
ON t1.schid = t2.schid
WHERE t1.type IN ('A', 'B');
This should retrieve only the table 2 records which match the criteria.
SELECT t2.*
FROM Table2 t2
JOIN Table1 t1 ON t1.schid = t2.schid
WHERE t1.type = 'A'
OR t1.type = 'B';
SELECT t2.*
FROM `Table2` t2
JOIN `Table1` t1 ON t2.`schid`=t1.`schid`
WHERE t1.`type` IN ('A','B');