I have 2 tables to be joined.
Table 1 is a master table and contains a unique set of rows.
ID DESCRIPTION
01 Alpha
02 Gamma
03 Delta
04 Beta
Table 2 is a detail table containing many rows with only some of the rows matching the master table.
ID INFO MASTER_ID
0001 abc 02
0002 def 02
0004 xyz 01
0005 mno 04
I want to JOIN the tables in order to produce the following result:
Alpha "has detail"
Gamma "has detail"
Delta "does not have detail"
Beta "has detail"
Rather than:
Alpha "has detail"
Gamma "has detail"
Gamma "has detail"
Delta "does not have detail"
Beta "has detail"
The later output is returning Gamma twice and I only want it returned once.
I tried LEFT JOIN, RIGHT JOIN, INNER JOIN and none of them produce my desired result.
Thanks for helping.
use LEFT JOIN probably you are missing something
SELECT CONCAT(a. description, IF(b.master_ID IS NOT NULL, ' has detail',' does not have detail'))
FROM table1 a
LEFT JOIN (SELECT DISTINCT master_ID FROM table2) b
ON a.ID = b.master_ID
SQLFIDDLE Demo
SQLFIDDLE Demo (with double quotes)
Maybe something like this:
SELECT
Table1.DESCRIPTION,
(
CASE
WHEN EXISTS(SELECT NULL FROM Table2 WHERE Table2.MASTER_ID=Table1.ID)
THEN 'has detail'
ELSE 'does not have detail'
END
) AS has
FROM
Table1
Just a different approach:
SELECT
table1.description,
IF((EXISTS(SELECT master_id from table2 where table2.master_id = table1.id)),
'has detail',
'does not have detail') As Status
FROM table1
SELECT a.Description, IF(b.Info, "has detail", "does not have detail") as Status
FROM Table_1 a
LEFT OUTER JOIN Table_2 b
ON a.MASTER_ID = b.MASTER_ID
GROUP BY 1,2;
If your output containts the detail part, then you have to either see both rows (as it'sa valid result) or you need to aggregate the results by selecting FIRST, MAX, etc.
If you don't need the detail values themselves, then alternative would be to do two SELECTs and use UNION:
SELECT DISTINCT Table1.Description, "does not have detail" as Comment
FROM Table1
LEFT JOIN Table2 ON (Table1.ID = MASTER_ID)
WHERE Table2.id IS NULL
UNION
SELECT DISTINCT Table1.Description, "has detail" as Comment
FROM Table1
LEFT JOIN Table2 ON (Table1.ID = MASTER_ID)
WHERE Table2.id IS NOT NULL
You can also achieve this using a groupby
SELECT a.Description, IF(count(b.id) > 0, "has detail", "does not have detail") as Status
FROM Table1 a
LEFT OUTER JOIN Table2 b
ON a.iD = b.MASTER_ID
GROUP BY a.Description ORDER BY a.Description ASC
Related
For dataset a
name
height
weight
Pen
155
45
Leo
172
50
Dan
180
60
Dataset b
name
nation
age
date of birth
Pen
China
22
15/10/1998
Pen
Italy
30
19/08/1990
Pen
Italy
30
30/01/1990
NULL
Japan
27
12/09/1993
I try to use the following code to join two data:
Select * From a
JOIN b
ON a.name = b.name;
How can I change my code so that I can keep everything on the a table by joining the name column in both dataset and also shows all the null value if it exists?
Following simple join on the name field can help you with that
SELECT * FROM a LEFT JOIN b ON a.name = b.name
The traditional way is to use an outer join.
Select *
From a LEFT OUTER JOIN b ON a.name = b.name
You don't need to specify OUTER, as "LEFT JOIN" will be the same in MySQL.
Select *
From a LEFT JOIN b ON a.name = b.name
Use whichever syntax you like, although in my opinion, adding the "OUTER" makes it clear to anyone reading the SQL that it's an outer join rather than an inner join.
I have a couple tables in MySQL DB
EID Name
1 Title A
2 Title B
3 Title C
LID EID Location Address Order
1 1 Office NY 1
2 1 Home IL 2
3 2 Office CA 1
4 3 Home NJ 2
I have the above 2 tables (Employee and Location). I would like to know the location of each Employee with office as a preferred choice and if 'office' does not exist then would need 'Home' location . The order column defined the order/priority of what is needed.
here is the output needed
EID LID Name Location Address
1 1 Title A Office NY
2 3 Title B Office CA
3 4 Title C Home NJ
The first join of the query below just connects the Employee and Location tables, but note that it results in all records from Location being joined. The critical part of the below query is the second INNER JOIN to a subquery. This subquery identifies the minimum (i.e. highest priority) order for each employee ID. This is then used to discard records from the first join which are not the highest priority.
SELECT t1.EID,
t2.LID,
t1.Name,
t2.Location,
t2.Address
FROM Employee t1
INNER JOIN Location t2
ON t1.EID = t2.EID
INNER JOIN
(
SELECT EID, MIN(`Order`) AS min_order
FROM Location
GROUP BY EID
) t3
ON t2.EID = t3.EID AND
t2.Order = t3.min_order
One other note: Don't name your columns Order, which is a MySQL keyword. To get my query to work, I had to put it in backticks, which is inconvenient to say the least, and possibly error prone.
Demo here:
SQLFiddle
There are two posibility to get your result.
1)If you need Based on Order result then use this query
SELECT e1.EID, l1.LID, e1.Name, l1.Location, l1.Address
FROM Employee e1
JOIN
(SELECT MIN(`Order `) as Minorder, EID, LID, Location, Address, Order
FROM Location l1
GROUP BY EID) l1
ON l1.EID = e1.EID AND l1.Minorder = l1.Order;
2)if you need result Based on EID then use this query
SELECT e1.EID,l1.LID,e1.Name,l1.Location,l1.Address
FROM Employee e1 JOIN
(SELECT MIN(`EID`)as Mineid,EID,LID,Location,Address,`Order` FROM Location l1 GROUP BY EID)l1
ON l1.Mineid = e1.EID;
Extra Note:-
Plese donot use mysql inbuilt keyword as Column name or Table name for more information read this link click here
You can the expected result by using inner join
Select a.eid,b.Lid,a.name,b.location,b.address from Table1 a innner join (select * from Tableb group by eid) b on
a.eid=b.eid;
you can try this code this will help you as i think
select E.EID,E.name,ad.LID,ad.LOCATION,ad.ADDRESS,ad.[order]
from #emp E inner join #address ad on E.EID = ad.EID
inner join (select EID, min([order]) [order]
from #address
group by EID) tt on ad.EID = tt.EIDand ad.[order] = tt.[order]
I'm trying to add a third INNER JOIN to a SELECT Query, where this third INNER JOIN needs to look for a value in that third Table, which value needs to be coupled with the outcome of a MAX + GROUP BY construct in the main SELECT Query. This may not be possible, I don’t know. I can't get it to work :-)
Example
TableA
User - Score
userA - 10
userB - 42
userC - 32
userB - 42
userB - 18
userD - 12
userB - 65
.
Table B
User - Color
userA - Green
userB - Yellow
userC - Blue
On these two tables I use a
SELECT
MAX(TableA.Score) AS MaxScore,
TableB.Color
FROM TableA
INNER JOIN TableB
ON TableA.User = TableB.User
GROUP BY TableA.User
The output here works nicely and is
User - MaxScore - Color
UserA - 10 - Green
UserB - 65 - Yellow
UserC - 32 - Blue
Now, I have a separate table where all the Scores get names.
TableC
Score - Name
5 - Quite Low
10 - OK
25 - Not bad
32 - Fairly good
50 - Well done
65 - Excellent
What I try to do is get a QUERY result which reads…
User - MaxScore - Name - Color
UserA - 10 - OK - Green
UserB - 65 - Excellent - Yellow
UserC - 32 - Fairly Good - Blue
My QUERY would look something like this…
SELECT
TableA.User
MAX(TableA.Score) AS MaxScore,
TableC.Name,
TableB.Color
FROM TableA
INNER JOIN TableB
ON TableA.User = TableB.User
INNER JOIN TableC
ON TableC.Score = (SELECT MAX(TableA.Score) AS MaxScore FROM Table A GROUP BY TableA.User) ThisSubQueryName
GROUP BY TableA.User
My problem is clearly with the syntax of the INNER JOIN of Table C, which INNER JOIN carries that subquery. I have no idea how to do this, or if it is even possible.
Looking forward to your wisdom.
Thanks :-)
Dutch
Try this instead:
SELECT mainQ.*, c.Name
FROM (
SELECT a.`User`, MAX(a.Score) AS MaxScore, b.Color
FROM TableA AS a
INNER JOIN TableB AS b ON a.`User` = b.`User`
GROUP BY a.`User`
) AS mainQ
INNER JOIN TableC AS c
ON mainQ.MaxScore = c.Score
Though your subquery could've worked with some modifications (involving table aliases and replacing it's GROUP BY with a WHERE), correlated subqueries are relatively expensive and often unnecessary.
Edit: Wow, after all that, I just realized I basically duplicated scaisEdge's answer's query; amazing how much a couple newlines can throw off your skimming ability.
You should use a dinamic table(t) and then the inner join on TableC
select t.User, t.MaxScore, c.Name, t.Color from (
SELECT
TableA.User as User
MAX(TableA.Score) AS MaxScore,
TableB.Color as Color
FROM TableA
INNER JOIN TableB
ON TableA.User = TableB.User
GROUP BY TableA.User
) t
INNER JOIN TableC on t.MaxScore = TableC.Score
Suppose I have the following table structure:
TABLE 1
main_id | type | information
first segway excellent
second car mercedes
third bike sliceofwind
TABLE segway
id | grade
1 excellent
2 bad
3 (...)
TABLE car
id | brand
1 mercedes
2 honda
3 (...)
TABLE bike
id | tires
1 sliceofwind
2 flatasfaque
3 (...)
What I'd like to do is dinamically obtain information from different tables based on type from table1.
Here's the generic example of a query that I've tried
SELECT (CASE
WHEN table1.type = 'segway' AND segway.grade = table1.information
THEN segway.id,
WHEN table1.type = 'car' AND car.brand = table1.information
THEN car.id,
WHEN table1.type = 'bike' AND bike.tires = table1.information
THEN bike.id
END) AS information
FROM table1,segway,bike,car WHERE table1.main_id IN ("ids")
The result of this query is a cartesian product because all the data from all tables will be retrieved despite the restrictions inside the case because not all tables have restrictions.
I'd like to know if there is a way to work around this without changing the table structure, and if not plea for some hints! (I'm up to some kinky sql stuff, what I'm asking here if it is indeed possible to do this, despite it being advised or not and why!).
This might be one way to do it.
SELECT t1.*
FROM table1 t1
LEFT JOIN segway s
on T1.main_id = s.id and T1.type= 'segway'
LEFT JOIN car c
on T1.main_id = c.id and T1.type= 'car'
LEFT JOIN bike b
on T1.main_id = b.id and T1.type= 'bike'
WHERE t1.main_ID in (SomeList)
segway, car, and bike table columns will be null when the Table1's type doesn't match.
However this seems like it would give you back more data/columns than you need. I think you'd be better off writing separate queries outside the database and call them depending on the value they select. OR using a procedure within the database and conditional logic to return the desired result set. (again 3 separate queries and conditional logic in the database) but without understanding use case, I can't really say which would be better.
We could further coalese the brand, tires and grade into a "Value" field as in
Select t1.*, coalese(s.grade,c.brand,b.tires) as value but I'm not sure this offers any help either.
if we needed to only return table 1 values and set values from the other tables... you said kinky, not me.
I can't see how the Cartesian would occur this way.
This will be your expected result, try this query..
SELECT (CASE WHEN s.`id` IS NOT NULL THEN s.`id`
WHEN c.`id` IS NOT NULL THEN c.`id`
WHEN b.`id` IS NOT NULL THEN b.`id`
END) AS information FROM table1 AS t1
LEFT JOIN segway s ON t1.type= 'segway'
LEFT JOIN car c ON t1.type= 'car'
LEFT JOIN bike b ON t1.type= 'bike'
WHERE t1.main_ID IN (1, 2, 3) AND (t1.information = s.`grade` OR
t1.`information`=c.brand OR
t1.`information`=b.tires);
I have two tables,
ID NAME
-------------------
12 Jon Doe
4 Jane Doe
9 Sam Doe
AND
MemID Cat# DateChkOut DateDue DateRet
4 T 430.98 1956 15-Mar-2011 14-Jun-2011 31-May-2011
12 B 125.2 2013 15-Mar-2011 14-Jun-2011
4 T 430.98 1956 27-Dec-2012 25-Mar-2013
Now I need to list the `members’ names who have never checked out a book.
SELECT Name FROM MEMBER, CHECKOUT WHERE ID != MemID;
did not work. Any suggestions?
You need to use a LEFT JOIN in this case.
Try the following:
SELECT M.Name
FROM MembersTable M
LEFT JOIN CheckoutTable C On C.MemId = M.ID
WHERE C.MemId IS NULL
Edit:
LEFT JOIN works in this situation because it joins the two tables on a common key - in this case the MemId. Since this is a LEFT JOIN it will take everything that exists in the Left table (Members) and if a match is found, it will include everything on the Right table (Checkout). But if no match is found in the Checkout table, everything on that side will be NULL.
So, all you would need to do is check to see if the Right side is NULL.
Hope this makes sense :)
SELECT name FROM member WHERE id NOT IN (SELECT MemID FROM checkout)
I think it should do the job
Use a correlated subquery with NOT EXISTS.
SELECT Name
FROM MEMBER a
WHERE NOT EXISTS(SELECT 1 FROM CHECKOUT b WHERE b.MemID = a.ID)
See Optimizing Subqueries with EXISTS Strategy.
If you use NOT IN in the query, that can be slow for large queries, try instead following using JOIN, which will be way faster:
SELECT MEMBER.NAME FROM MEMBER
LEFT JOIN CHECKOUT ON CHECKOUT.MemID = MEMBER.ID
WHERE CHECKOUT.MemID IS NULL:
Because you may want more fields returned an outer join is good method of accomplishing this.
SELECT Name
FROM MEMBER M
LEFT JOIN CHECKOUT C
on M.ID = C.MemID
WHERE C.MemID is null;
Try this:
SELECT M.ID,M.Name
FROM MEMBER M LEFT JOIN
CHECKOUT C ON C.MemID=M.ID
WHERE C.DateRet IS NULL
It will select the user details whose DateRet is null.
Sample result:
ID NAME
-------------------
12 Jon Doe
4 Jane Doe
You have to use a where in and check for the DateChkOut:
SELECT Name
FROM MEMBER
WHERE ID not in
( select MemID
from CHECKOUT
where DateChkOut is not null
)
SELECT id,
name
FROM Member
WHERE id NOT IN
(SELECT memid
FROM checkout)
or
SELECT id,
name
FROM member m
LEFT OUTER JOIN checkout c ON m.id = c.memid
WHERE c.memid IS NULL