Special Join On 1 to N mapped columns - mysql

This question is an extension of AJC's Join On 1 to N mapped columns.
What if EMPLOYEE_DETAILS is like this:
+---------+-------------+--------------+
| EMP_ID | AREA_CODE | SECTOR_CODE |
+---------+-------------+--------------+
| 1223 | 5001 | 1001 |
| 3224 | (NULL) | 2001 |
| 3225 | 6001 | (NULL) |
+---------+-------------+--------------+
Then how would it be possible to map the respective names like this output:
+---------+-------------+--------------+
| EMP_ID | AREA_NAME | SECTOR_NAME |
+---------+-------------+--------------+
| 1223 | AREA 1 | SECTOR 1 |
| 3224 | (NULL) | SECTOR 2 |
| 3225 | AREA 2 | (NULL) |
+---------+-------------+--------------+
I thought about doing a union of joins like so,
select e.emp_id, a.LOCATION_NAME as area, s.LOCATION_NAME as sector
from EMPLOYEE_DETAILS e
join LOCATION_DETAILS a on a.id = e.AREA_CODE
join LOCATION_DETAILS s on s.id = e.SECTOR_CODE
union
select e.emp_id, a.LOCATION_NAME as area, NULL as sector
from EMPLOYEE_DETAILS e
join LOCATION_DETAILS a on a.id = e.AREA_CODE
union
select e.emp_id, NULL as area, s.LOCATION_NAME as sector
from EMPLOYEE_DETAILS e
join LOCATION_DETAILS s on s.id = e.SECTOR_CODE;
But then this would require me to use this as an internal query to get the expected result.
Is there a more concise way to go about doing this?

Why not left join twice?
select e.emp_id, a.location_name as area, s.location_name as sector
from employee_details e
left join location_details a on a.id = e.area_code
left join location_details s on s.id = e.sector_code

I can advice solution with single join like:
select
e.emp_id,
group_concat(if(ld.id = e.area_code, ld.location_name, null)) as area,
group_concat(if(ld.id = e.sector_code, ld.location_name, null)) as sector
from EMPLOYEE_DETAILS e
left join LOCATION_DETAILS ld
on (ld.id = e.area_code or ld.id = e.sector_code)
group by e.emp_id;
Here the fiddle: SQLize.online

Related

MySQL get the sum with left joins

I've three tables.
REGIONS
CUISINE
BANNERS
If I run this query
SELECT SUM(fee) FROM BANNERS;
Output will be 10,000
If I run this query
SELECT SUM(fee) FROM CUISINE;
Output will be 12,800
But if I run this query
SELECT REGIONS.name,
sum(BANNERS.fee) as banner_revenue,
sum(CUISINE.fee) as cuisine_revenue
FROM REGIONS
LEFT JOIN BANNERS ON REGIONS.id = BANNERS.region_id
LEFT JOIN CUISINE ON REGIONS.id = CUISINE.region_id
GROUP BY REGIONS.name;
Output is wrong. My desired output is
name | banner_revenue | cuisine_revenue
------------------------------------------
NY | 10,000 | 4,800
Paris | NULL | 8,000
London | NULL | NULL
DB fiddle reproduce
Why could this happen?
Please refer my DB fiddle.
If you run
SELECT *
FROM REGIONS
LEFT JOIN BANNERS
ON REGIONS.id = BANNERS.region_id
LEFT JOIN CUISINE
ON REGIONS.id = CUISINE.region_id;
you'll notice, that for every region banner pair all the cusines are join, thus "multiplying" the cuisins. I.e. their fees also multiply.
Do the grouping in the derived tables and join them to get your desired result.
SELECT r.name,
sb.fee,
sc.fee
FROM REGIONS r
LEFT JOIN (SELECT sum(b.fee) fee,
b.region_id
FROM BANNERS b
GROUP BY b.region_id) sb
ON sb.region_id = r.id
LEFT JOIN (SELECT sum(c.fee) fee,
c.region_id
FROM CUISINE c
GROUP BY c.region_id) sc
ON sc.region_id = r.id;
Consider the following:
SELECT r.name
, x.header
, x.fee
FROM REGIONS r
LEFT
JOIN
( SELECT 'banner' header, region_id, fee FROM banners
UNION
SELECT 'cuisine', region_id, fee FROM cuisine
) x
ON x.region_id = r.id
ORDER
BY r.name;
+--------+---------+------+
| name | header | fee |
+--------+---------+------+
| London | NULL | NULL |
| NY | cuisine | 2500 |
| NY | cuisine | 2300 |
| NY | banner | 2000 |
| NY | banner | 5000 |
| NY | banner | 3000 |
| Paris | cuisine | 8000 |
+--------+---------+------+

How to use joins in MySQL in this case

I have an employee table and a department table. How to can I use join to get the required below result. manager_id in the employee table is nothing but the employee id. Please help me to find out the answer
Employee Table
id | name | manager_id | department_id
----------------------------------------
1 | A | NULL | 1
2 | B | 1 | 2
3 | C | NULL | 3
4 | D | 3 | 2
Department Table
id | department_name
-------------------------
1 | Admin
2 | HR
3 | Finance
Required OutPut
id | name | manager_name | department_name
-----------------------------------------------
1 | A | NULL | Admin
2 | B | A | HR
3 | C | NULL | Finance
4 | D | C | HR
Use both Inner join and outer join
select E1.ID, E1.Name, E2.Name, D.department_name
FROM Employee E1
LEFT OUTER JOIN Employee E2 ON E2.ID = E1.manager_id
INNER JOIN Department D ON D.id = E1.department_id
SELECT E1.id, E1.name, E2.name as manager_name, D1.department_name
FROM Employee E1
LEFT JOIN Employee E2 ON (E1.id = E2.manager_id)
JOIN Department D2 ON (E1.department_id = D1.id)
You need first do the self join to find the manager name and after that nee to join with the Department to find the appropriate Department name.
This will help you.
SELECT e.id as id, e.name as name e.manager_id as manager_id,
d.department_name as department_name
FROM Employee as e
JOIN Department as d
ON e.department_id = d.id

writing advanced sql query

I am working with this schema: http://classes.engr.oregonstate.edu/eecs/winter2013/cs275-400/tester/bsgSchema.html
and I am trying to achieve: Find the fname, lname and ship_instance id of all people who do not have Viper certificaton but are assigned to at least one instance of a Viper class ship (this includes all variants of Viper class ships). Return a row for every ship/person combination.)
I am close. I have written the following query:
SELECT DISTINCT p.fname, p.lname, si.id from bsg_people p
INNER JOIN bsg_ship_assignment sa ON sa.pid = p.id
INNER JOIN bsg_ship_class sc ON sc.id = sa.cid
INNER Join bsg_ship_instance si ON si.class = sa.cid
WHERE p.id NOT
IN (
SELECT cp.pid
FROM bsg_cert_people cp
INNER JOIN bsg_cert c ON c.id = cp.cid
WHERE cp.cid = '2'
)
AND sc.name = 'viper'
My query returns a number of extra instances.
SELECT p.fname
, p.lname
, sk.id
FROM bsg_people p
LEFT
JOIN bsg_cert_people cp
ON cp.pid = p.id
LEFT
JOIN bsg_cert c
ON c.id = cp.cid
AND c.title = 'viper'
JOIN bsg_ship_assignment ps
ON ps.pid = p.id
JOIN bsg_ship_instance sk
ON sk.id = ps.sid
AND sk.class = ps.cid
JOIN bsg_ship_class k
ON k.id = sk.class
WHERE k.name = 'viper'
AND c.id IS NULL;
+---------+----------+------+
| fname | lname | id |
+---------+----------+------+
| William | Adama | 8757 |
| Lee | Adama | 121 |
| Lee | Adama | 289 |
| Lee | Adama | 1104 |
| Laura | Roslin | 2343 |
| Gaius | Baltar | 289 |
| Samuel | Anders | 3203 |
| Samuel | Anders | 8757 |
| Brendan | Costanza | 7242 |
| Brendan | Costanza | 2343 |
+---------+----------+------+
SELECT bsg_people.fname, bsg_people.lname, bsg_ship_instance.id FROM bsg_people
INNER JOIN bsg_ship_assignment ON bsg_ship_assignment.pid = bsg_people.id
INNER JOIN bsg_ship_instance ON bsg_ship_assignment.sid = bsg_ship_instance.id
INNER JOIN bsg_ship_class ON bsg_ship_class.id = bsg_ship_instance.class
WHERE bsg_people.id NOT IN
(
SELECT bsg_cert_people.pid FROM bsg_cert_people
INNER JOIN bsg_cert ON bsg_cert_people.cid = bsg_cert.id
WHERE bsg_cert.title = 'Viper'
)
AND bsg_ship_class.name = 'viper'

How to do one select two query with join table

I have two table as follows:
- tblEmployee
employeeID | Name
10 | sothorn
20 | lyhong
30 | sodaly
40 | chantra
50 | sangha
60 | bruno
- tblSale
ID | employeeID | employeeSaleID
1 | 30 | 10
2 | 10 | 40
3 | 50 | 20
I would like to select from tableSale and join with tblEmployee result that:
1 | sodaly | sothorn
2 | sothorn | chantra
3 | sangha | lyhong
Here is a sample query on your data.
http://sqlfiddle.com/#!2/b74ca/5/0
Simply select all rows of the tblSale table, and join tblEmployee table twice:
SELECT s.ID, e1.Name, e2.Name
FROM tblSale s
INNER JOIN tblEmployee e1
ON e1.employeeID = s.employeeID
INNER JOIN tblEmployee e2
ON e2.employeeID = s.employeeSaleID
Try this:
Here you need to use inner join to get data from both tables.
select
id, e1.name as name1, e2.name as name2
from
tblSale s, tblEmployee e1, tblEmployee e2
where
s.employeeID=e1.employeeID
and
s.employeeSaleID=e2.employeeID
order by
s.id
Thanks
This is simple
QUERY
SELECT
tblSale.ID,
l.Name,
r.Name
FROM tblSale
INNER JOIN tblEmployee l On l.employeeID = tblSale.employeeID
INNER JOIN tblEmployee r ON r.employeeID = tblSale.employeeSaleID
FIDDLE
OUTPUT
| ID | LNAME | RNAME |
|----|---------|---------|
| 1 | sodaly | sothorn |
| 2 | sothorn | chantra |
| 3 | sangha | lyhong |
just join the employee table twice, once to employeeID, once to employeeSaleID

MYSQL Query : How to UNION two table with ORDER BY

can anyone help me solve this problem? i've been trying to query this but i keep getting error.
MySQL code:
SELECT * FROM
(
SELECT BU.*, BD.BOOK_TITLE AS BOOK_TITLE, BD.BOOK_COMPANY AS COMPANY,
BD.RETURN_DATE AS RETURN
FROM BOOK_USER BU
INNER JOIN BOOKING_DETAIL BD ON (BU.USR_ID = BD.USR_ID)
UNION
SELECT BU.*, "NEW REGISTERED" AS BOOK TITLE, 'RENT-A-BOOK' AS COMPANY,
BU.REGISTER_DATE AS RETURN
FROM BOOK_USER BU
) AS BU
GROUP BY BU.USR_ID
The Tables:
BOOK_USER
+---------+----------+---------------+
| USR_ID | USR_NAME | REGISTER_DATE |
+---------+----------+---------------+
| 1 | john | 2011-09-20 |
+---------+----------+--------------+
| 2 | jane | 2011-12-05 |
+---------+----------+--------------+
| 3 | doe | 2012-02-16 |
+---------+----------+--------------+
| 4 | mary | 2012-02-02 |
+---------+----------+--------------+
BOOKING_DETAIL
+---------+----------+------------+-----------+--------------+
| BOOK_ID | USR_ID | BOOK_TITLE | COMPANY | RETURN_DATE |
+----------+--------+-------------+-----------+--------------+
| 1 | 1 | DEAR JOHN |ABC PVT LMT| 2011-11-01 |
+---------+---------+-------------+-----------+--------------|
| 2 | 1 | LUCKY | DEF | 2012-03-18 |
+---------+---------+-------------+-----------+--------------|
| 3 | 1 | THE RISE | GHI | 2012-06-12 |
+---------+---------+-------------+-----------+--------------|
| 4 | 2 | HELLO | TIMES | 2012-01-11 |
+---------+---------+-------------+-----------+--------------|
| 5 | 2 | SHOPAHOLIC | | 2012-08-31 |
+---------+---------+-------------+-----------+--------------|
| 6 | 3 | LOST | | 2012-06-20 |
+---------+---------+-------------+-----------+--------------|
The result should return the latest RETURN_DATE and SORTED by USR_ID.
eg:
John, THE RISE, GHI,2012-06-12
Jane,SHOPAHOLIC,RENT-A-BOOK,2012-08-31
doe, LOST,RENT-A-BOOK,2012-06-20
mary, NEW REGISTERED,RENT-A-BOOK , 2012-02-02
The query constains a subquery which gets the latest RETURN_DATE for each user.
SELECT a.*, c.BOOK_TITLE, c.RETURN_DATE
FROM book_user a
INNER JOIN
(
SELECT usr_ID, MAX(return_DATE) maxDate
FROM booking_detail
GROUP BY usr_ID
) b ON a.usr_ID = b.usr_ID
INNER JOIN booking_detail c
ON b.usr_ID = c.usr_ID AND
b.maxDate = c.return_DATE
SQLFiddle Demo
UPDATE
use LEFT JOIN and COALESCE
SELECT a.USR_ID,
a.USR_NAME,
COALESCE(c.BOOK_TITLE,'RENT-A-BOOK') BOOK_TITLE,
COALESCE(c.RETURN_DATE, a.REGISTER_DATE) RETURN_DATE
FROM book_user a
LEFT JOIN
(
SELECT usr_ID, MAX(return_DATE) maxDate
FROM booking_detail
GROUP BY usr_ID
) b ON a.usr_ID = b.usr_ID
LEFT JOIN booking_detail c
ON b.usr_ID = c.usr_ID AND
b.maxDate = c.return_DATE
SQLFiddle Demo
Try that :
SELECT *
FROM (
(
SELECT BU.*, BD.BOOK_TITLE, BD.BOOK_COMPANY AS COMPANY,BD.RETURN_DATE AS RETURN FROM BOOK_USER BU INNER JOIN BOOKING_DETAIL BD ON (BU.USR_ID = BD.USR_ID)
) UNION ALL (
SELECT BU.*, BD.BOOK_TITLE, 'RENT-A-BOOK' AS COMPANY,BD.RETURN_DATE AS RETURN FROM BOOK_USER BU INNER JOIN BOOKING_DETAIL BD ON (BU.USR_ID = BD.USR_ID)
)
) BU
GROUP BY BU.USR_ID
You can directly get the output using following query check the query:
SELECT BU.*, IFNULL(BD.BOOK_TITLE, 'NEW REGISTERED') AS BOOK_TITLE, IFNULL(BD.BOOK_COMPANY, 'RENT-A-BOOK') AS COMPANY,BD.RETURN_DATE AS RETURN
FROM BOOK_USER BU
LEFT JOIN (SELECT * FROM (SELECT USR_ID, BOOK_TITLE, BOOK_COMPANY, RETURN_DATE FROM BOOKING_DETAIL ORDER BY RETURN_DATE DESC) AS A GROUP BY USR_ID) AS BD ON (BU.USR_ID = BD.USR_ID)
ORDER BY BU.USR_ID;