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

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

Related

SQL query to get 2 values from table 1 and join all possible option from table 2

I want to get value from table1 and join all matching value from table2. The table1 has to be limited to 2 rows, but expecting output should own all matching values for those two ids.
How can I achieve this?
You would use a subquery:
select t1.*, t2.*
from (select t1.*
from table1 t1
limit 10
) t1 left join
table2 t2
on t1.id = t2.table1_id;
Note: This returns two arbitrary rows. Normally, you would have an order by to better specify the rows. And use order by rand() for random rows.
if you want all the value in join for only two row of table 1 you can use a subqiuery with limit 2
select b.id, a.value, b.value2, b.table1_ID
from (
select * from table1
limit 2
) a
inner join table2 on aid = b.table1_ID

How to remove common records found in 2 tables?

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

Have a left join where duplicates in the second table is involved - MYSQL

Table 1:
user score
------------
A 1
B 2
Table 2:
user comment time
----------------------------
A good <timestamp 1>
A bad <timestamp 2>
B average <timestamp 3>
I want to join these two tables such that I get the below:
user score comment
-------------------------
A 1 good
B 2 average
As you can see I'll need to join the second table's comment based on the timestamp (the most recent timestamp). I tried
SELECT st.user as user,st.score,
case when v.comment is null then 'NA' else v.comment end as comment
FROM tale1
left JOIN (select distinct user,comment,max(time) from table2) v ON st.user=v.user
but this doesnt work.
You can join with a correlated subquery that filters on the latest timestamp:
select
t1.*,
t2.comment
from table1 t1
left join table2 t2
on t2.user = t1.user
and t2.time = (
select max(t22.time)
from table2 t22
where t21.user = t1.user
)
Side note: I am unsure that you do need a left join here (your sample data does not demonstrate that).
You only want one column from table2 so I recommend a correlated subquery:
select t1.*,
(select t2.comment
from table2 t2
where t2.user = t1.user
order by t2.time desc
limit 1
) as comment
from table1 t1;
This query will make optimal use of an index on table2(user, time desc, comment) -- alas, though, I think the desc is ignored in MySQL.

Use selected column in first query with IN clause in second query

Problem has been recreated below:
/* query - 1 */
Select id, title from table1;
/* returns */
id | title
-----------
1 | data-1
2 | data-2
3 | data-3
4 | data-4
5 | data-5
I want use this column id's data with IN clause in second query along with join.
Something like this:
Select id, title from table1
JOIN
Select anotherColumn from table2 where table2.id IN (1,2,3,4,5) on table1.id = table2.id
Instead of manually writing 1,2,3,4,5, how can I use the column data selected from first query in second query?
EDIT:
Actual query :
SELECT *
FROM
(
SELECT R.id, U.ic_id as rider, U.name, DP.department_name, R.location,
(R.distance - 1) + 10 as cost , R.timestamp, R.status
FROM requests AS R, iconnect.users AS U, iconnect.departments AS DP
WHERE R.pool = '125' AND R.rider = U.ic_id AND U.department = DP.id
) requestDetails
JOIN
(
SELECT AVG(rider_rating) AS rider_rating,rider
FROM
(
SELECT rider_rating, R.rider
FROM journeys AS J, requests AS R
WHERE J.req_id = R.id AND R.rider IN (12,13) LIMIT 999999
) AS allRatings
GROUP BY rider
) ratingsTable
ON requestDetails.rider = ratingsTable.rider
/* instead of (12,13) I want to use requestDetails.rider selected from the first derived table */
One option would be to use an EXISTS clause:
SELECT id, title
FROM table1 t1
WHERE EXISTS (SELECT 1 FROM table2 t2 WHERE t1.id = t2.id);
Actually, a plain inner join between the two tables would also work. But, you might want to use SELECT DISTINCT in case a given record in table1 could match more than one record in table2. That would leave us with this:
SELECT DISTINCT t1.id, t1.title
FROM table1 t1
INNER JOIN table2 t2
ON t1.id = t2.id;

Join two tables with the same columns

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