Joining tables using MySQL - mysql

Sorry for bad title, but I don't know what is should be.
I want to join two tables but the number of line should be same as table one.
Here are my tables
====Table 1=====
| Name | IdCardNo |
===============
| Peter | 1234 |
| Mary | 5678 |
===============
==========Table 2=========
| IdCardNo | phoneNo | Job |
=========================
|1234|11111111|Student|
|1234|11111111|Waiter|
|5678|22222222|Student|
=========================
Here is the result i want
Peter|1234|11111111|
Mary|5678|22222222|
However if i do SELECT NAME, PhoneNo FROM Table1 LEFT JOIN Table2 on Table1.IdCardNo=Table2.IdCardNo
I get this
Peter|1234|11111111|
Peter|1234|11111111|
Mary|5678|2222222|
I know I can do GROUP BY NAME but I don't think it is a good idea.
What query should I use?
I think SELECT DISTINCT... is the thing I want. Thank you!

Just use DISTINCT
The SELECT DISTINCT statement is used to return only distinct
(different) values.
Something like
SELECT DISTINCT NAME, PhoneNo
FROM Table1 LEFT JOIN
Table2 on Table1.IdCardNo=Table2.IdCardNo
Maybe you might want to reconsider the design of the tables. Unless a different (possible) number is required per instance of table2, you might want to store the number in table1?

Your expected result is ambiguous
Mary|5678|11111111|
I suppose should be
Mary|5678|22222222|
This could be achieved as
select
t1.Name,
t1.IdCardNo,
t2.phoneNo
from table1 t1
join table2 t2 on t1.IdCardNo = t2.IdCardNo
group by t1.Name,t1.IdCardNo,t2.phoneNo

SELECT distinct t1.NAME, t1.idCardNo, t2.PhoneNo FROM Table1 t1 LEFT JOIN Table2 t2 on t1.IdCardNo=t2.IdCardNo
Distinct will skip identical rows in the result set!

'Select distinct' will only populate the joined table with unique values. Try that and let me know.

Related

Connection between tables [duplicate]

This question already has answers here:
SQL left join vs multiple tables on FROM line?
(12 answers)
Closed 2 years ago.
I would like to know what is the best way to create a connection between two tables (or more).
I have seen two different ways to do so.
In the next example, I have 2 tables. Table1 has customerId (key) and customerName. Table2 has customerId (key) and CustomerPhone
table1:
customerId | customerName|
============+=============+
1 | Josh |
2 | Nadia |
table2:
customerId | customerPhone|
============+==============+
1 | 123 |
2 | 456 |
Which query is the best and why:
SELECT Table1.customerId, Table2.customerPhone
FROM Table1, Table2
WHERE Table1.customerId = Table2.customerId
Query2:
SELECT Table1.customerId, Table2.customerPhone
FROM Table1
Inner Join Table2 ON Table1.customerId = Table2.customerId
The second option is more common and considered to be the right one, however they are both doing the same thing under the hood
The first query makes first a cross join and then reduces the result to fit the where cflause.
The second matches the tables by check ing if the condition in the ON clause ist met.
Both do the same, but the first is slowe
The first query is written using old syntax (SQL-89):
SELECT Table1.customerId, Table2.customerPhone
FROM Table1, Table2
WHERE Table1.customerId = Table2.customerId
The second query is written in modern syntax (SQL-92):
SELECT Table1.customerId, Table2.customerPhone
FROM Table1
Inner Join Table2 ON Table1.customerId = Table2.customerId
They are equivalent. Use SQL-92. Use SQL-92!

How to get multiple columns data into the same cell with a SQL query?

I need get an sql result that gets multiple columns data from a table into a single cell for the result. How would be the query?
Let's suppose I have this 2 tables:
Table 1:
Name spec
--------------
James front
--------------
Henry front
--------------
Henry back
Table 2:
Name dir
--------------
James 123
--------------
Henry 456
And I want to get this result:
Result Table:
Name spec dir
-----------------------
James front 123
-----------------------
Henry front 456
back
-----------------------
You can try using group_concat() function
select a.name, group_concat(spec SEPARATOR ' '),dir
from table1 a inner join table2 b on a.name=b.name
group by a.name,dir
The Solution for that problem is calling a join. A join combines multiple tables into one using certain identifiers. In your problem the identifier is the name. An example solution would be:
select table1.name, table2.spec, table2.dir
from table1 inner join table2 on table1.name = table2.name
Example: GROUP_CONCAT is correct, but if you want spec column value print in new line then use '\n'
SELECT a.name, GROUP_CONCAT(spec SEPARATOR '\n'),dir
FROM table1 a INNER JOIN table2 b ON (a.name=b.name)
GROUP BY a.name,dir;

sql: select rows which have the same column value in another column with a single query

example table:
id | value
----------
1 | abc
1 | cb3
1 | dsf
2 | sss
2 | d3
So if the input is "cb3" I want to get all rows with id 1, if the input is "sss" I want to get all rows with id 2. Can this be done with one query instead of two ? (first query is find id and second query bring rows for found id). Also, would a one query approach be faster ?
Thank you in advance.
you could try this :
SELECT *
FROM TABLE my_table
WHERE id IN (SELECT id
FROM TABLE my_table
WHERE value = input
)
Try the following, where you replace 'sss' with the value you are searching for:
select * from table t1
where t1.id in (select id from table t2 where value = 'sss')
Note that value seems not to be a key, such that you might get two different groups of ids in your result. That's also the reason why I proposed an t1.id IN (select id ... rather than an t1.id = (select id ....
You can solve it using inner join also.
SELECT S.*
FROM dataset AS S
INNER JOIN dataset AS T
ON S.id = T.id
WHERE T.value = 'cb3';

MySQL - select records from two tables, but only if there is no duplicate

I have two tables:
table1
#id_table1 | code1
#---------------------
# 1 | abc
# 2 | abcd
# 3 | abcde
table2
#id_table2|code2
#--------------------
# 1 | aaa
# 2 | bbb
# 3 | abcde
If i want to join this two tables and get records which are in both tables:
SELECT table1.code1, table2.code2 FROM table1, table2
WHERE table1.code1=table2.code2
Result: abcde
It's easy, but now I need to do the opposite : I want records from table1.code1 which aren't in table2.code2
Result i need: abc, abcd
And records from table2.code2, which aren't in table1.code1
Result i need: aaa, bbb
I would appriciate any help - thanks in advance!
Actually just noticed this is tagged specifically for MySQL, which doesn;t support FULL OUTER JOIN (if you are on another SQL system that supports this, you can skip on down for preferred approach.
So, in MySQL you need to UNION together both a left and right join like this:
SELECT
table1.code1,
table2.code2
FROM table1
LEFT JOIN table2 ON table1.code1=table2.code2
WHERE table2.code2 IS NULL
UNION
SELECT
table1.code1,
table2.code2
FROM table1
RIGHT JOIN table2 ON table1.code1=table2.code2
WHERE table1.code1 IS NULL
If you have FULL OUTER JOIN compatibility, you would perform the FULL OUTER JOIN and look for cases where the join results in null records on the field you are trying to join on.
SELECT
table1.code1,
table2.code2
FROM table1
FULL OUTER JOIN table2 ON table1.code1=table2.code2
WHERE table1.code1 IS NULL OR table2.code2 IS NULL
Here is a well-known article explaining how to perform different types of joins: http://blog.codinghorror.com/a-visual-explanation-of-sql-joins/
Quite simple actually:
SELECT code1
FROM table1 LEFT JOIN table2
ON table1.code1 = table2.code2
WHERE code2 IS NULL
And the same with the opposite table

left join returning more than expected

Using the following query
select *
from table1
left join table2 on table1.name = table2.name
table1 returns 16 rows and table2 returns 35 rows.
I was expecting the above query to return 16 rows because of the left join, but it is returning 35 rows. right join also returns 35 rows
Why is this happening and how do I get it to return 16 rows?
LEFT JOIN can return multiple copies of the data from table1, if the foreign key for a row in table 1 is referenced by multiple rows in table2.
If you want it to only return 16 rows, one for each table 1 row, and with a random data set for table 2, you can use just a plain GROUP BY:
select *
from table1
left join table2 on table1.name = table2.name
group by table1.name
GROUP BY aggregates rows based on a field, so this will collapse all the table1 duplicates into one row. Generally, you specify aggregate functions to explain how the rows should collapse (for example, for a number row, you could collapse it using SUM() so the one row would be the total). If you just want one random row though, don't specify any aggregate functions. MySQL will by default just choose one row (note that this is specific to MySQL, most databases will require you to specify aggregates when you group). The way it chooses it is not technically "random", but it is not necessarily predictable to you. I guess by "random" you really just mean "any row will do".
Let's assume you have the following tables:
tbl1:
|Name |
-------
|Name1|
|Name2|
tbl2:
|Name |Value |
--------------
|Name1|Value1|
|Name1|Value2|
|Name3|Value1|
For your LEFT JOIN you'll get:
|tbl1.Name|tbl2.Name|Value |
----------------------------
|Name1 | Name1 |Value1|
|Name1 | Name1 |Value2|
|Name2 | NULL | NULL |
So, LEFT JOIN means that all records from LEFT (first) table will be returned regardless of their presence in right table.
For your question you need to specify some specific fields instead of using "*" and add GROUP BY tbl1.Name - so your query will look like
select tbl1.Name, SOME_AGGREGATE_FUNCTION(tbl2.specific_field), ...
from table1
left join table2 on table1.name = table2.name
GROUP BY tbl1.Name
One way to use this is by using the power of SQL distinct.
select distinct tbl1.id, *
from table1 tbl1
left join table2 tbl2 on tbl2.name = tbl1.name
where
....................
Please not that I am also using aliasing.
If the name column is not unique in the tables then you may simply have duplicates on table2.
Try running:
select * from table2 where name not in (select name from table1);
If you get no results back then duplicates on the name column is the reason for the extra rows coming back.
Duplication may be reason. See example in the post
https://alexpetralia.com/posts/2017/7/19/more-dangerous-subtleties-of-joins-in-sql
if you want to join the single latest/earliest relative row from right table, you can limit the join data using min/max primary key and then limiting to 1 row using group Like this:
SELECT * FROM table1
LEFT JOIN (SELECT max(tbl2_primary_col), {table2.etc} FROM table2 GROUP BY name) AS tbl2
ON table1.name = tbl2.name
WHERE {condition_for_table1}
And remember don't use * for left join because it will disable min/max and always return first row.
As per your comment "A random row from table2, as long as name from table1 matches name from table2", you can use the following:
select table1.name, (select top 1 somecolumn from table2 where table2.name = table1.name)
from table1
Note that top 1 is not mysql but it is for SQL Server