Join two tables with the same columns - mysql

There are two tables T1 and T2. Both of them have 3 columns and 2 of them are the same with the same data in both tables. Let them be an ID, C1, C2 in the T1 and C1, C2, COM in the T2 table.
The thing is that all C1 data is present in T2, but C2 data can be missed.
I need to return a table with COM for each ID.
Tried
SELECT T1.ID, T2.COM
FROM T1
LEFT JOIN T2 ON T1.C1 = T2.C1;
but it returns incorrect results.

So as a summary: You need one and only one COM by ID (even If it doesn't exist in the second table) and you want the ID sorted ascending.
You need to add a join condition:
SELECT CAST(T1.ID as UNSIGNED) as ID, T2.COM
FROM T1
LEFT JOIN T2 ON T1.C1 = T2.C1
AND (T1.C2 = T2.C2) -- The first condition of this row is to handle the null value
OR (T1.C2 NOT IN (SELECT C2 FROM T2) AND T2.C2 = 'NA')
ORDER BY CAST(T1.ID as UNSIGNED) -- To convert to int and sort ascending
Edit: To order the result ascending, you need to convert the ID into Integer and then order the result. Here is some documentation.
Edit2: Here it is for 3 and 4 it's the better method I think but I do not advise to do that usually

Related

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;

Mysql: select value that matches several criteria on multiple rows

Good evening,
I have two tables t1 and t2
In t1, I have two variables, ID (which uniquely identify each row) and DOC (which can be common to several IDs)
In t2, I have three variables, ID (which does not necessarily uniquely identify the rows here), AUTH , and TYPE. Each ID has a maximum of 1 distinct AUTH.
Sample data:
What I would like to do is to select the DOCs that have an ID with AUTH='EP', and that also have an ID with AUTH='US'. They could have additional IDs with other AUTH, but they have to have at least these two.
Thus, i would have a final table with the DOC, ID,and AUTH (there should be at least 2 IDs per doc, but it can be more if there exists an additional AUTH to US and EP for this DOC)
The desired results:
This should work:
SELECT DISTINCT (T1.ID), T1.DOC, T2.AUTH FROM T1
LEFT JOIN T2 ON T2.ID = T1.ID
WHERE T1.DOC IN( SELECT T1.DOC FROM T2
LEFT JOIN T1 ON T1.ID = T2.ID
WHERE T2.AUTH IN('EP','US')
GROUP BY T1.DOC HAVING COUNT(DISTINCT T2.AUTH) = 2) ;
If I could understand correctly the query is going to be something like that:
select t1.doc, t1.id, t2.auth from t1
left join t2 on t2.id = t1.id
where t1.doc in( select t1.doc from t2
left join t1 on t1.id = t2.id
where t2.auth in('EP','US') );
Although, the result set is basically going to be the first sample data table, due to the ID 6 which has a AUTH = "EP" and, consequently, the ID 7 which has the same DOC from ID 6.

How can I compare if 2 tables have the same data?

If I have 2 tables and want to find if they have the same data, what is the most straightforward way to do it in MySQL?
I have read about doing a correlated subquery and UNION ALL but this query is about 2 pages (!) and can not really follow what it is doing. There must be an easier way.
Even if it is e.g. make MySQL copy the table data to files and do a vimdiff (I am not sure that this is even possible -is it?- just thinking out loud).
UPDATE
I am interested only in the table data and not structure. This is to clarify due to an ambiguous comment I made
If you just want to tell whether the tables are identical or not as efficiently as possible, use this query:
SELECT 1 FROM (
SELECT * FROM table1
UNION ALL
SELECT * FROM table2
) t
GROUP BY col1, col2, col3
HAVING count(*) = 1
LIMIT 1
List all the columns in GROUP BY to compare the entire table.
If the result is an empty set, the two tables are identical.
If you want to see the differences, use this query:
SELECT * FROM (
SELECT 'table1' tname, col1, col2, col3 FROM table1
UNION ALL
SELECT 'table2' tname, col1, col2, col3 FROM table2
) t
GROUP BY col1, col2, col3
HAVING count(*) = 1
List the same columns in the inner SELECT as in the GROUP BY, plus a column to distinguish the two tables.
Just throwing this out there, you could emulate a full outer join and then return the rows where just the right or the left side is null.
select t1.*
from table1 t1
LEFT OUTER JOIN table2 t2
ON t1.col1 = t2.col1
AND t1.col2 = t2.col2
AND ...
WHERE t2.id is null
UNION
select t2.*
from table2 t2
LEFT OUTER JOIN table1 t1
ON t2.col1 = t1.col1
AND t2.col2 = t1.col2
AND ...
WHERE t1.id is null
With the FULL OUTER JOIN you can show all rows where the other row is not available in the other table.
Use the following query:
SELECT c1 = cjoin AND c2 = cjoin equiv
FROM (SELECT COUNT(*) c1 FROM Table1) t1,
(SELECT COUNT(*) c2 FROM Table2) t2,
(SELECT COUNT(*) cjoin
FROM Table1 t1
JOIN Table2 t2
ON t1.col1 = t2.col1 AND t1.col2 = t2.col2 AND t1.col3 = t2.col3 ...) tjoin
Assuming the tables have a unique key, this will return equiv = 1 if the tables are equal. It doesn't show the differences, it's just a binary test.
I was reading SQL Cookbook from A.Molinaro, when I came across a solution.
It is based on to tables
emp(empno,ename,job,mgr,hiredate,sal,comm,deptno)
and a view
V
which has the same columns but different rows. The columns mgr and comm might be NULL, other columns not.
The solution in the book is very long and it does not show all differences, although this was the stated problem in 3.7.
I made up my solution which is shorter and shows all differences (means all rows which have different counts in the two tables).
select * from
# those which are contained in the (distinct) union of (col1,col2,...,coln, count) of both tables:
( select empno,ename,job,mgr,hiredate,comm,deptno, count(*) cnt from emp group by empno,ename,job,mgr,hiredate,comm,deptno
union
select empno,ename,job,mgr,hiredate,comm,deptno, count(*) cnt from V group by empno,ename,job,mgr,hiredate,comm,deptno
) as unionOfBoth
where (empno,ename,job,mgr,hiredate,comm,deptno,cnt)
not in
# those which are contained in the intersection of both tables with the equal number of counts:
( select e.empno,e.ename,e.job,e.mgr,e.hiredate,e.comm,e.deptno,e.cnt
from
(select empno, ename,job,mgr,hiredate,comm,deptno, count(*) cnt from emp group by empno,ename,job,mgr,hiredate,comm,deptno) e,
(select empno, ename,job,mgr,hiredate,comm,deptno, count(*) cnt from V group by empno,ename,job,mgr,hiredate,comm,deptno) v
where
e.empno = v.empno
and e.ename = v.ename
and e.job = v.job
and ifnull(e.mgr,0) = ifnull(v.mgr,0)
and e.hiredate = v.mgr
and e.deptno = v.deptno
and ifnull(e.comm,0) = ifnull(v.comm,0)
and e.cnt = v.cnt
);
Basically you count the distinct rows in both tables and do a union (not union all) to get the tmp.table unionBoth. Then you remove those rows, which both tables have in common.
Here two rows r1 from table t1 and r2 from table t2 are considered the same, if
(r1,count of r1 in t1) = (r2, count of r2 in t2), which is equivalent to r1=r2 (on all columns) and (count of r1 in t1) = (count of r2 in t2).
If the tables are small enough, you can export both tables as csv files and then copy one of the tables and paste them side-by-side with the other table. You can just go row by row and see if the outputs are the same that way.

Merge two queries and return one of the possible values

select value1 as value from T1 where id=10;
if id does not exist in T1 - execute another query:
select value2 as value from T2 where id=10;
So, I want to join these queries and return a single value (value1 or value2). Is it possible?
SOLUTION:
My solution:
select ifnull(value1, value2) as value from T1 left join T2 using(id) where id=10;
you can join the query using union
select value1 as value from T1 where id=10
union
select value2 as value from T2 where id=10;
as a result you can get any one of the value or both
TRY (tested)
SELECT COALESCE(t1.value1, t2.value2) AS Value FROM t1
INNER JOIN t2 USING(id)
WHERE id=10
this will always check first the table t1 for id=10, if there is no value then see table t2 for the same id
Quoted FROM
The single result column that replaces two common columns is defined
using the coalesce operation. That is, for two t1.a and t2.a the
resulting single join column a is defined as a = COALESCE(t1.a, t2.a)
You can join the two queries on the id field and then use the COALESCE function to combine the two resulting fields into the output.
This assumes that you already have a list of IDs to join against, though. Otherwise you're stuck doing a union or full join to get such a list first.
You Can use this too
select Distinct(s1.id) from sample1 as s1 inner join sample2 as s2;
use union of both
like below :
select t1.id from table1 as t1 where id=10
union
select t2.id from table2 as t2 where id=10