I have a mysql table like this
+---------+----------------+-------+------------+
| dept_id | parent_dept_id | level | name |
+---------+----------------+-------+------------+
| 1 | 0 | 0 | Company |
| 2 | 1 | 1 | HR |
| 3 | 1 | 1 | Finance |
| 4 | 1 | 1 | Operations |
| 5 | 4 | 2 | Sales |
| 6 | 2 | 2 | Training |
+---------+----------------+-------+------------+
I am trying to retrieve all departments and their parent departments. But what I also want is to retrieve the deprtment with ID 1. This guy is the top department and does not have a parent, all I want is a null in the department name.
So far I have this query
select
d1.dept_id,
d2.name as parent_name,
d1.parent_dept_id,
d1.level,
d1.name
from
tdept d1,
tdept d2
where
d1.parent_dept_id = d2.dept_id;
Currently, all departments get retrieved except for the top one, how can I achieve this?
Try using the LEFT OUTER JOIN (The LEFT JOIN keyword returns all rows from the left table (table1), with the matching rows in the right table (table2). The result is NULL in the right side when there is no match.)
select
d1.dept_id,
d2.name as parent_name,
d1.parent_dept_id,
d1.level,
d1.name
from tdept d1
Left outer join tdept d2
where d1.parent_dept_id = d2.dept_id;
Ok, I got it working, I did this:
select
d1.dept_id,
d2.name as parent_name,
d1.parent_dept_id,
d1.level,
d1.name
from
tdept d1 left outer join tdept d2 on d1.parent_dept_id = d2.dept_id;
Thanks Nadeem_MK for putting me in the right direction
Crouz
Try something like this:
select
t1.dept_id,
t2.name,
t1.parent_dept_id,
t1.level,
t1.name
from tdept t1
Left outer join tdept t2
ON t1.parent_dept_id = t2.dept_id;
Related
I would like to extract the number of attendances (i.e., COUNT()) of "Coaches" at "Shows" happening during two separate months: March and April. I managed to create a query that collects that number over only one of the months. In addition, via slightly modifying the query, the numbers over the second month can be found easily. But how do I merge them into one table containing both columns?
So, given the two queries and resulting tables below, how would one "append" the result of Query 2 to the result of Query 1? In other words, how would one combine their respective SELECT statements?
I included links to the SQL fiddle in case you need them.
Thank you in advance.
SQL Fiddle
Query 1:
SELECT C.*, COUNT(CIS.idCoach) AS MarchNumOfShows
FROM Coach AS C
LEFT JOIN
(
CoachInShow AS CIS
LEFT JOIN
TVShow AS S
ON S.idShow = CIS.idShow
)
ON C.idCoach = CIS.idCoach AND S.airDate LIKE '_____04___'
GROUP BY C.idCoach
Results:
| idCoach | name | surname | MarchNumOfShows |
|---------|-----------|---------|-----------------|
| 1 | Stephen | Hawking | 5 |
| 2 | Nicholas | Cage | 7 |
| 3 | Sigourney | Weaver | 6 |
Query 2 (Minimal difference, querying for April instead of March):
SELECT COUNT(CIS.idCoach) AS AprilNumOfShows
FROM Coach AS C
LEFT JOIN
(
CoachInShow AS CIS
LEFT JOIN
TVShow AS S
ON S.idShow = CIS.idShow
)
ON C.idCoach = CIS.idCoach AND S.airDate LIKE '_____05___'
GROUP BY C.idCoach
Results:
| AprilNumOfShows |
|-----------------|
| 8 |
| 7 |
| 10 |
Wanted:
| idCoach | name | surname | MarchNumOfShows | AprilNumOfShows |
|---------|-----------|---------|-----------------|-----------------|
| 1 | Stephen | Hawking | 5 | 8 |
| 2 | Nicholas | Cage | 7 | 7 |
| 3 | Sigourney | Weaver | 6 | 10 |
You are very close, the last step you missed is simply combine MarchNumOfShows and AprilNumOfShows with left join.
like below codes (or look into the Sql Fiddle ):
SELECT C.idCoach, C.name, C.surname, COUNT(distinct CIS4.idShow) AS MarchNumOfShows
, COUNT(distinct CIS5.idShow) AS AprilNumOfShows
FROM Coach AS C
LEFT JOIN
(
CoachInShow AS CIS4
LEFT JOIN
TVShow AS S4
ON S4.idShow = CIS4.idShow
)
ON C.idCoach = CIS4.idCoach AND S4.airDate LIKE '_____04___'
LEFT JOIN
(
CoachInShow AS CIS5
LEFT JOIN
TVShow AS S5
ON S5.idShow = CIS5.idShow
)
ON C.idCoach = CIS5.idCoach AND S5.airDate LIKE '_____05___'
GROUP BY C.idCoach;
And below is another way to get the same output (or look into SQL Fiddle):
SELECT C.idCoach, C.name, C.surname,
sum(case when DATE_FORMAT(airDate,'%M')='April' then 1 else null end ) AS AprilNumOfShows,
sum(case when DATE_FORMAT(airDate,'%M')='May' then 1 else null end ) AS MayNumOfShows
FROM Coach AS C
LEFT JOIN
(
CoachInShow AS CIS
LEFT JOIN
TVShow AS S
ON S.idShow = CIS.idShow
)
ON C.idCoach = CIS.idCoach
GROUP BY C.idCoach;
one way to do it is with a case:
select *,
sum(case when airdate like "%03%" then 1 else 0 end) as March,
sum(case when airdate like "%04%" then 1 else 0 end) as April
...
I want to ask ..
If i have data but data related in another table
but i want the output is display all data
usually if data related in another table, I using INNER JOIN but the output just data have a relation, if dont have relation, its not display .. IF I using LEFT JOIN or RIGHT JOIN not all data displayed .. IF I using UNION data duplicated
this just example field .. field in real so many
TABLE A
ID | NAMA |
----------------------
1 | Rina |
2 | Deni |
3 | Muti |
4 | Sina |
5 | Sasa |
TABLE B
ID | Rumah |
----------------------
1 | Jabar |
2 | Jateng |
3 | Jatim |
OUTPUT THAT I WANT
ID | NAMA | Rumah
----------------------------------
1 | Rina | Jabar
2 | Deni | Jateng
3 | Muti | Jatim
4 | Sina | -
5 | Sasa | -
short version:
SELECT COALESCE(a.ID, t2.ID),
COALESCE(a.NAMA, '-')
COALESCE(b.Rumah, '-')
FROM TableA a
LEFT JOIN TableB b
ON a.ID = b.ID
RIGHT JOIN TableB t2
ON a.ID = b.ID
If I understand your problem correctly, then a given ID might only have a first or last name, but not both. In this case, simply doing a left or right join will result in the loss of data. One approach here is to do a full outer join between your two tables on the ID, and then use COALESCE to handle possibly missing data appropriately.
SELECT COALESCE(t1.ID, t2.ID) AS ID,
COALESCE(t1.NAMA, '-') AS NAMA,
COALESCE(t2.Rumah, '-') AS Rumah
FROM TableA t1
LEFT JOIN TableB t2
ON t1.ID = t2.ID
UNION
SELECT COALESCE(t1.ID, t2.ID),
COALESCE(t1.NAMA, '-')
COALESCE(t2.Rumah, '-')
FROM TableA t1
RIGHT JOIN TableB t2
ON t1.ID = t2.ID
i have table like this:
table1:
id | item_name | entered_by | modify_by
1 | banana | 2 | 1
2 | apple | 4 | 3
3 | orance | 1 | 1
4 | pineapple | 5 | 3
5 | grape | 6 | 1
table2:
id | username
1 | admin
2 | jack
3 | danny
4 | dummy
5 | john
6 | peter
the query is work fine to select if the entered_by or modify_by do have value:
SELECT t1.id, t1.item_name,
t2enteredBy.username enteredBy,
t2modifyBy.username modifyBy
FROM table1 t1
JOIN table2 t2enteredBy ON t1.entered_by = t2enteredBy.id
JOIN table2 t2modifyBy ON t1.modify_by = t2modifyBy.id
problem: if one of the modifiy_by or entered_by field have null value, the row is now showing out, i need it to show it out as '-' if it has null value rather than hide the row completely.
SQLFIDDLE HERE
Try this out:
SELECT t1.id, t1.item_name,
COALESCE(t2enteredBy.username, '-') enteredBy,
COALESCE(t2modifyBy.username, '-') modifyBy
FROM table1 t1
LEFT JOIN table2 t2enteredBy ON t1.entered_by = t2enteredBy.id
LEFT JOIN table2 t2modifyBy ON t1.modify_by = t2modifyBy.id
Fiddle here.
You need a left join to return those rows with null values. Then the coalesce will make sure that they are replaced by the given string if they are null.
Try this - use LEFT JOIN instead of JOIN
SELECT t1.id, t1.item_name,ifnull(t2enteredBy.username,'-') enteredBy,
ifnull(t2modifyBy.username,'-') modifyBy
FROM table1 t1
LEFT JOIN table2 t2enteredBy ON t1.entered_by = t2enteredBy.id
LEFT JOIN table2 t2modifyBy ON t1.modify_by = t2modifyBy.id
SQL Fiddle Here
I need to perform a FULL OUTER JOIN on two tables and I'm trying to implement it in MySQL using the LEFT JOIN/RIGHT JOIN/UNION ALL technique.
Here are the original tables:
giving_totals:
+--------------+---------------+-------------+
| country_iso2 | total_given | supersector |
+--------------+---------------+-------------+
| AE | 1396986989.02 | 3 |
| AE | 596757809.20 | 4 |
| AE | 551810209.87 | 5 |
| AE | 25898255.77 | 7 |
| AE | 32817.63 | 9 |
...
+--------------+---------------+-------------+
receiving_totals:
+--------------+----------------+-------------+
| country_iso2 | total_received | supersector |
+--------------+----------------+-------------+
| AE | 34759000.00 | 3 |
| AE | 148793.82 | 7 |
| AE | 734.30 | 9 |
| AF | 6594479965.85 | 1 |
| AF | 2559712971.26 | 2 |
+--------------+----------------+-------------+
I want the resulting table to have one entry for each country for each supersector code even if it did not give or receive money for that sector (this is from the AidData project dataset in case anyone is familiar.) I thought to accomplish this by doing a UNION of a LEFT JOIN (to get all giving entries) and RIGHT JOIN (to get all receiving entries.) Here's the query I tried:
SELECT g.country_iso2 AS country_iso2, g.total_given AS `total_given`,R.total_received AS `total_received`,g.supersector AS `supersector`
FROM (`giving_totals` `g`
LEFT JOIN `receiving_totals` `r`
ON(((g.country_iso2 = r.country_iso2)
AND (g.supersector = r.supersector))))
UNION ALL
SELECT g.country_iso2 AS country_iso2, g.total_given AS `total_given`,R.total_received AS `total_received`,g.supersector AS `supersector`
FROM (`giving_totals` `g`
RIGHT JOIN `receiving_totals` `r`
ON(((g.country_iso2 = r.country_iso2)
AND (g.supersector = r.supersector))))
But this only returns the first join, whether or not I put the right or left join first. I think I may be misunderstanding the UNION operation because the individual joins each return what I expected. Any help is appreciated as always.
Here is an alternative method to do a full outer join:
SELECT driver.country_iso2 AS country_iso2,
g.total_given AS `total_given`,
R.total_received AS `total_received`,
driver.supersector AS `supersector`
from ((select distinct country_iso2, supersector
from giving_totals
) union
(select distinct country_iso2, supersector
from receiving_totals
)
) driver left outer join
giving_totals gt
on gt.country_iso2 = driver.country_iso2 and
gt.supersector = driver.country_iso2 left outer join
receiving_totals rt
on rt.country_iso2 = driver.country_iso2 and
rt.supersector = driver.country_iso2
That is, do the union as a subquery to get all the combinations you are interested in. Then you can do a left outer join to that table.
The reason for your problem is that aliases in the second query. You can try this instead:
SELECT r.country_iso2 AS country_iso2, g.total_given AS `total_given`,R.total_received AS `total_received`,r.supersector AS `supersector`
FROM (`giving_totals` `g`
RIGHT JOIN `receiving_totals` `r`
ON(((g.country_iso2 = r.country_iso2)
AND (g.supersector = r.supersector))))
The original form would have NULLs for these values.
I feel like I was always taught to use LEFT JOINs and I often see them mixed with INNERs to accomplish the same type of query throughout several pieces of code that are supposed to do the same thing on different pages. Here goes:
SELECT ac.reac, pt.pt_name, soc.soc_name, pt.pt_soc_code
FROM
AECounts ac
INNER JOIN 1_low_level_term llt on ac.reac = llt.llt_name
LEFT JOIN 1_pref_term pt ON llt.pt_code = pt.pt_code
LEFT JOIN 1_soc_term soc ON pt.pt_soc_code = soc.soc_code
LIMIT 100,10000
Thats one I am working on:
I see a lot like:
SELECT COUNT(DISTINCT p.`case`) as count
FROM FDA_CaseReports cr
INNER JOIN ae_indi i ON i.isr = cr.isr
LEFT JOIN ae_case_profile p ON cr.isr = p.isr
This seems like the LEFT may as well be INNER is there any catch?
Is there any catch? Yes there is -- left joins are a form of outer join, while inner joins are a form of, well, inner join.
Here's examples that show the difference. We'll start with the base data:
mysql> select * from j1;
+----+------------+
| id | thing |
+----+------------+
| 1 | hi |
| 2 | hello |
| 3 | guten tag |
| 4 | ciao |
| 5 | buongiorno |
+----+------------+
mysql> select * from j2;
+----+-----------+
| id | thing |
+----+-----------+
| 1 | bye |
| 3 | tschau |
| 4 | au revoir |
| 6 | so long |
| 7 | tschuessi |
+----+-----------+
And here we'll see the difference between an inner join and a left join:
mysql> select * from j1 inner join j2 on j1.id = j2.id;
+----+-----------+----+-----------+
| id | thing | id | thing |
+----+-----------+----+-----------+
| 1 | hi | 1 | bye |
| 3 | guten tag | 3 | tschau |
| 4 | ciao | 4 | au revoir |
+----+-----------+----+-----------+
Hmm, 3 rows.
mysql> select * from j1 left join j2 on j1.id = j2.id;
+----+------------+------+-----------+
| id | thing | id | thing |
+----+------------+------+-----------+
| 1 | hi | 1 | bye |
| 2 | hello | NULL | NULL |
| 3 | guten tag | 3 | tschau |
| 4 | ciao | 4 | au revoir |
| 5 | buongiorno | NULL | NULL |
+----+------------+------+-----------+
Wow, 5 rows! What happened?
Outer joins such as left join preserve rows that don't match -- so rows with id 2 and 5 are preserved by the left join query. The remaining columns are filled in with NULL.
In other words, left and inner joins are not interchangeable.
Here's a rough answer, that is sort of how I think about joins. Hoping this will be more helpful than a very precise answer due to the aforementioned math issues... ;-)
Inner joins narrow down the set of rows returns. Outer joins (left or right) don't change number of rows returned, but just "pick up" additional columns if possible.
In your first example, the result will be rows from AECounts that match the conditions specified to the 1_low_level_term table. Then for those rows, it tries to join to 1_pref_term and 1_soc_term. But if there's no match, the rows remain and the joined in columns are null.
An INNER JOIN will only return the rows where there are matching values in both tables, whereas a LEFT JOIN will return ALL the rows from the LEFT table even if there is no matching row in the RIGHT table
A quick example
TableA
ID Value
1 TableA.Value1
2 TableA.Value2
3 TableA.Value3
TableB
ID Value
2 TableB.ValueB
3 TableB.ValueC
An INNER JOIN produces:
SELECT a.ID,a.Value,b.ID,b.Value
FROM TableA a INNER JOIN TableB b ON b.ID = a.ID
a.ID a.Value b.ID b.Value
2 TableA.Value2 2 TableB.ValueB
3 TableA.Value3 3 TableB.ValueC
A LEFT JOIN produces:
SELECT a.ID,a.Value,b.ID,b.Value
FROM TableA a LEFT JOIN TableB b ON b.ID = a.ID
a.ID a.Value b.ID b.Value
1 TableA.Value1 NULL NULL
2 TableA.Value2 2 TableB.ValueB
3 TableA.Value3 3 TableB.ValueC
As you can see, the LEFT JOIN includes the row from TableA where ID = 1 even though there's no matching row in TableB where ID = 1, whereas the INNER JOIN excludes the row specifically because there's no matching row in TableB
HTH
Use an inner join when you want only the results that appear in both tables that matches the Join condition.
Use a left join when you want all the results from Table A, but if Table B has data relevant to some of Table A's records, then you also want to use that data in the same query.
Use a full join when you want all the results from both Tables.
For newbies, because it helped me when I was one: an INNER JOIN is always a subset of a LEFT or RIGHT JOIN, and all of these are always subsets of a FULL JOIN. It helped me understand the basic idea.