Select values from one table based on two other tables (relational) - mysql

I have 3 tables one with company details, one with officer details and one that connects those two Company_Officer by ID so I can tell which officer works for which company and he can also work for multiple companies and a company can have multiple workers.
I am trying to create a query that would give me ID of the company that Officer works for company_Id, officers name and his role. The company he works for must have company_index set to FTSE 100 his status officer_resigned must be set to 0 and also he must work for more than 1 company.
Something like:
Company_ID|Company_Name|Officer_Name|Officer_Role
--------------------------------------------------
1 | Apple PLC |Millis, John|Director
1 | Apple PLC |DLAMINI, Bob|Secretary
2 | Google PLC |Millis, Johm|Secretary
Company_Details:
Officer_Details:
Company_Officer:
I have started fiddling with sql but it does not make much sense to me when it comes to relational databases. I understand that I need to use join. Is it all possible to achieve with one query?

Another sql for extra constraint of "getting only those officers which work for more than 1 company".
SELECT cd.company_id,
cd.company_name,
od.officer_name,
co.officer_role
FROM COMPANY_DETAILS cd
inner join COMPANY_OFFICER co
ON cd.company_id = co.company_id
inner join OFFICER_DETAILS od
ON co.officer_id = od.officer_id
WHERE cd.company_index = 'FTSE 100' AND
od.officer_resigned = '0' AND
co.officer_id IN
( SELECT officer_id
FROM COMPANY_OFFICER
GROUP BY officer_id
HAVING Count( DISTINCT company_id ) > 1
);

SELECT
CD.company_id,
CD.company_name,
OD.officer_name,
CO.officer_role
FROM
company_details CD
INNER JOIN company_officer CO
ON CD.company_id = CO.company_id
INNER JOIN officer_details OD
ON CO.officer_id = OD.officer_id
WHERE CD.company_index='FTSE 100' AND
OD.officer_resigned='0';

Do you even need to join?
SELECT DISTINCT c.Company_ID, c.Company_Name, o.Officer_Name, o.Officer_Role
FROM Company_Details c, Officer_Details o, Company_Officer co
WHERE Company_Index = 'FTSE 100' AND Officer_Resigned = 0 AND co.Officer_ID = o.Officer_ID AND co.Company_ID = c.Company_ID

Simply use inner join between the 3 table
select
Company_Details.Company_ID
, Company_Details.Company_Name
, Officer_Details.Officer_Name
, Company_Officer.Officer_Role
from Company_Details
INNER JOIN Officer_Details on Officer_Details.Officer_ID = Company_Officer.Officer_ID
INNER JOIN Company_Officer on Company_Officer.Company_ID = Company_Details.Company_ID;

Related

MySQL error #1111 - Invalid use of group function

Yes, this is an assignment. So the task was to output two columns of 'first name' and 'last name' with conditions:
-A u (B ∩ -C ∩ -(A ∩ -( B u D)))
A: All consumers that didn't shop on Monday and Friday
(time_by_day.the_day)
B: All consumers who bought 'Non-Consumable'
(product_class.product_family)
C: All consumers who bought more than 10 items
(sales_fact_1997.unit_sales) at one time (sales_fact_1997.time_id)
D: Female consumers from Canada (consumer.gender, consumer.country)
This is what I got so far
SELECT
c.fname,
c.lname
FROM
customer AS c
INNER JOIN sales_fact_1997 AS s ON c.customer_id = s.customer_id
INNER JOIN time_by_day AS t ON s.time_id = t.time_id
INNER JOIN product AS p ON s.product_id = p.product_id
INNER JOIN product_class AS pc ON p.product_class_id = pc.product_class_id
Where
NOT t.the_day in ('Monday', 'Friday') OR
(
pc.product_family = 'Non-Consumable' AND
NOT SUM(s.unit_sales) > 10 AND
NOT (
t.the_day in ('Monday', 'Friday') AND
NOT (
pc.product_family = 'Non-Consumable' OR
(c.country = 'Canada' AND c.gender = 'F')
)
)
)
GROUP BY concat(c.customer_id, s.time_id)
That ended up with an error
#1111 - Invalid use of group function
But I don't know which part of the code is wrong. I'm pretty sure that it's probably the WHERE part. But I don't know what I did wrong.
Condition C is where I'm really struggling. I manage just fine making a query of C
SELECT
t.time_id,
c.customer_id,
c.fullname,
round(SUM(s.unit_sales),0) as tot
FROM
customer as c
INNER JOIN sales_fact_1997 as s ON c.customer_id = s.customer_id
INNER JOIN time_by_day as t on s.time_id=t.time_id
GROUP BY concat(c.customer_id, s.time_id)
ORDER BY c.customer_id, t.time_id
But trying to incorporate it into the main code is hard for me.
Reading online I assume that I should probably use HAVING instead of WHERE.
I would really appreciate it if someone can point me in the right direction.
This is the database that I used.
C: All consumers who bought more than 10 items
(sales_fact_1997.unit_sales) at one time (sales_fact_1997.time_id)
You should use COUNT not SUM.
SELECT time_id,
count(*)
FROM sales_fact_1997
GROUP BY time_id
HAVING COUNT(*)>=10 ;
count(*) is not needed, I let just to show the results
Can you try if it helps:
SELECT c.lname,
c.fname
FROM customer c
INNER JOIN
(
SELECT time_id,customer_id,product_id
FROM sales_fact_1997
GROUP BY time_id,customer_id,product_id
HAVING COUNT(*)>=10
) as s on c.customer_id=s.customer_id
INNER JOIN
(
SELECT time_id,the_day
FROM time_by_day
WHERE the_day
NOT IN ('Monday','Friday')
) as t on s.time_id=t.time_id
INNER JOIN
(
SELECT product_family,product_id
FROM product_class
INNER JOIN product
on product_class.product_class_id=product.product_class_id
WHERE product_family='Non-Consumable'
) pc on s.product_id=pc.product_id
where c.country='Canada' and c.gender ='F' ;

join between two tables with != condition

I have two tables
courses_available:
Course | language
-----------------
A | English
A | Spanish
courses_enrolled
Name |course | language
--------------------------
PersonA | A | English
PersonB | A | Spanish
PerconC | A | French
I want to write a query to gives me records where a person is taking a course in an language that it is not offered in. In the above example, PersonC is taking course A in French but its only offered in English & Spanish.
select p.name, p.course, p.language from courses_available c, courses_enrolled p where p.course=c.course and p.language != c.language.
The above query is giving me course A as well. What kind of join will give me only C?
i hope it helps. Just use "<>" instead of !=
Example:
SELECT * FROM courses_available
LEFT JOIN courses_enrolled ON courses_available.course = courses_enrolled.course
WHERE courses_available.language <> courses_enrolled.language
No need to use '!=' you can add one more on condition
select ce.* from course c inner join courses_enrolled ce
on
c.Course = ce.Course
and
c.Language = ce.Language
you can see in sqlFiddle
use left join with condition b.language is null
select p.name, p.course, p.language
from courses_enrolled a left join courses_available b
on a.course=b.course and a.language = b.language
where b.language is null
Use not exists
Select enrolled.*
From enrolled
Where.not exists (
Select 1
From courses
Where courses.id = enrolled.id
And courses.language = enrolled.language
)
You can't do this by joining where language doesn't match, you want to join where it does match but only select rows where, with a left join, no courses_available is found:
select p.name, p.course, p.language
from courses_enrolled p
left join courses_available c on p.course=c.course and p.language = c.language
where c.course is null

How to avoid repetitions of columns in MySQL subquery?

i am retrieving the result from above 4 table using following query
SELECT
(SELECT SUM(CASE when c.Training_Id=1 then 1 else 0 end)
FROM courses c
INNER JOIN enrolled_students es
ON c.Course_Id = es.Course_Id
) STEM,
(SELECT SUM(CASE when c.Training_Id=2 then 1 else 0 end)
FROM courses c
INNER JOIN enrolled_students es ON c.Course_Id = es.Course_Id
) MA,
c.* FROM campus c;
The problem with this query is, two(2) students are in STEM and one(1) Student in MA against Campus_Id 3, but its repeating records against all campuses. i want if campus has no students than there should be '0' Zero.
You need to filter your subselects by Campus_Id. But first you have to use distinct table aliases. Change your last line to ca.* FROM campus ca. Then you can use a where clause in your subselects (WHERE c.Campus_Id = ca.Campus_Id).
SELECT
(SELECT SUM(CASE when c.Training_Id=1 then 1 else 0 end)
FROM courses c
INNER JOIN enrolled_students es
ON c.Course_Id = es.Course_Id
WHERE c.Campus_Id = ca.Campus_Id -- line added
) STEM,
(SELECT SUM(CASE when c.Training_Id=2 then 1 else 0 end)
FROM courses c
INNER JOIN enrolled_students es ON c.Course_Id = es.Course_Id
WHERE c.Campus_Id = ca.Campus_Id -- line added
) MA,
ca.* FROM campus ca; -- line changed
This should solve your problem.
To improve the performance you can also filter your subselects by Training_Id. In the first subselect you only need the rows with Training_Id=1. So you can change your where clause to:
WHERE c.Campus_Id = ca.Campus_Id
AND c.Training_Id = 1
Doing that you can also use COUNT instead of SUM. So your subselect would look like:
SELECT COUNT(1)
FROM courses c
INNER JOIN enrolled_students es ON c.Course_Id = es.Course_Id
WHERE c.Campus_Id = ca.Campus_Id AND c.Training_Id = 1
To prevent code duplication (your subselects are almost equal) you can join all needed tables and group by Campus_Id:
select
COUNT(co.Training_Id=1 OR NULL) STEM,
COUNT(co.Training_Id=2 OR NULL) MA,
ca.Campus_Id
from campus ca
left join courses co on co.Campus_Id = ca.Campus_Id
left join enrolled_students es on es.Course_Id = co.Course_Id
where co.Training_Id in (1, 2)
group by ca.Campus_Id

Multiple Join Searching in Database

I want to fetch the records from database in my ongoing project.
I have 5 Tables; Everyone make profile which is saved in starting four tables then define partner profile. I want to to fetch all the partner name which meets profile.
This is my tables structure:
Basic Info (reg_id, name, gender, dob, martial_status)
Education (id,reg_id,education,college)
Location (id,reg_id,country,state, city)
Other_details (id,reg_id,height, weight)
Partner (id, reg_id, gender, dob, education, college, country, state, city, height, weight,martial_status) [ This is the Main Table]..
So far I tried this but no luck:
SELECT `basic_info`.`reg_id`,
`basic_information`.`dob`,
`other_detail`.`height`,
`location`.`city`,
`education`.`education`
FROM `basic_information`
INNER JOIN(
SELECT *
FROM `patner`
WHERE `patner`.`reg_id`='shi01') `patner`
ON `basic_information`.`martial_status`=`partner`.`martial_status`
AND `basic_information`.`reg_id`!='shi01'
INNER JOIN `education`
ON `patner`.`education`=`education`.`education`
AND `patner`.`education`=`education`.`education`
INNER JOIN `location`
ON `patner`.`city`=`location`.`city`
INNER JOIN `other_detail`
ON `patner`.`bodytype`=`other_detail`.`body_type`
AND `patner`.`skin`=`other_detail`.`skin`
AND `patner`.`height1` <= `other_detail`.`height`
GROUP BY `basic_information`.`reg_id`;
You did some mistakes in writing join conditions. I have tried to fix it. Try this, It should work;
SELECT BI.reg_id, BI.name
FROM basic_info BI
INNER JOIN
Education E ON BI.reg_id = E.reg_id
INNER JOIN
Location L ON BI.reg_id = L.reg_id
INNER JOIN
Other_details OD ON BI.reg_id = OD.reg_id
INNER JOIN
(Select reg_id, martial_status, height, education, city FROM Partner where reg_id = 'Your_ID') P
ON BI.reg_id = P.reg_id
WHERE
BI.marital_status = P.marital_Status
AND E.Education = P.Education
AND L.city = P.City
AND OD.height <= P.Height
AND BI.reg_id <> 'Your_ID';

mysql: Group Concat with joined tables and values that aren't unique

I have an issue where I need to aggregate and concatenate multiple row data into single row output. I understand the tables are a problem in that their is no unique index, but I need to do this at the query level instead of the scripting level and I can't touch the database structure.
Here we go:
table: characteristics
id code_a code_b
-------------------------------
2201 CHAU AIRS
2201 CHAU PELC
2201 PROX AUTO
2201 PROX HOP`
table: characteristics_types
code description
-------------------------------
CHAU Heating System
PROX Nearby
table: characteristics_sub_types
code_a code description
-------------------------------
CHAU AIRS Forced Air
CHAU PELC Baseboard
PROX AUTO Highway
PROX HOP Hospital
Result required:
id Heating System Nearby
--------------------------------------------------------
2201 Forced Air, Baseboard Highway, Hospital
Not working:
SELECT id,
(case when C.code_a='CHAU' THEN GROUP_CONCAT(STC.description) ELSE NULL END) AS Heating System,
(case when C.code_a='PROX' THEN GROUP_CONCAT(STC.description) ELSE NULL END) AS Nearby
from characteristics C
inner join characteristics_types TC on C.code_a=TC.`code`
inner join characteristics_sub_types STC on C.code_a=STC.code_a and C.code_b=STC.`code`
GROUP BY C.id,C.code_a
I am getting the following results:
id Heating System Nearby
--------------------------------------------------------
2201 Forced Air, Baseboard NULL
2201 NULL Highway, Hospital
Any direction would be greatly appreciated!
GROUP_CONCAT accepts a DISTINCT keyword which is useful in fan-out-queries. You can also use ORDER BY within a GROUP_CONCAT if you need your results to be ordred. See Documentation. Using this, we can write your intended query like below:
SELECT
c.id,
GROUP_CONCAT(DISTINCT ct.description) as 'Heating System',
GROUP_CONCAT(DISTINCT cst.description) as 'Nearby'
FROM characteristics c
LEFT JOIN characteristics_types ct ON ct.id = c.id
LEFT JOIN characteristics_sub_types cst
ON cst ON cst.code_a = c.code_a AND cst.code = c.code_b
GROUP BY 1
I would write separate subqueries, each one preforming the group_concat that you need, and join them together. Individually, I wrote them like this:
SELECT c.id, GROUP_CONCAT(cst.description) AS 'Heating System'
FROM characteristics c
JOIN characteristics_sub_types cst ON cst.code_a = c.code_a AND cst.code = c.code_b AND c.code_a = 'CHAU'
GROUP BY c.id;
And the join like this:
SELECT c.id, t1.`Heating System`, t2.`Nearby`
FROM(
SELECT c.id, GROUP_CONCAT(cst.description) AS 'Heating System'
FROM characteristics c
JOIN characteristics_sub_types cst ON cst.code_a = c.code_a AND cst.code = c.code_b AND c.code_a = 'CHAU'
GROUP BY c.id) t1
JOIN(
SELECT c.id, GROUP_CONCAT(cst.description) AS 'Nearby'
FROM characteristics c
JOIN characteristics_sub_types cst ON cst.code_a = c.code_a AND cst.code = c.code_b AND c.code_a = 'PROX'
GROUP BY c.id) t2 ON t1.id = t2.id;
Here is a working SQL Fiddle.
You can try this way:
SELECT c.id,
GROUP_CONCAT(STC.description_heating) AS `Heating System`,
GROUP_CONCAT(STC.description_nearby) AS Nearby
from characteristics C
inner join characteristics_types TC on C.code_a=TC.`code`
inner join (
SELECT code_a, code,
CASE WHEN code_a = 'CHAU' THEN description ELSE null END as descriptio_heating,
CASE WHEN code_a = 'PROX' THEN description ELSE null END as descriptio_nearby,
FROM characteristics_sub_types
) as STC on C.code_a=STC.code_a and C.code_b=STC.`code`
GROUP BY C.id
SELECT c.id,
GROUP_CONCAT(STC.description_heating) AS `Heating System`,
GROUP_CONCAT(STC.description_nearby) AS Nearby
from characteristics C
inner join characteristics_types TC on C.code_a=TC.`code`
inner join (
SELECT code_a, code,
CASE WHEN code_a = 'CHAU' THEN description ELSE null END as description_heating,
CASE WHEN code_a = 'PROX' THEN description ELSE null END as description_nearby
FROM characteristics_sub_types
) as STC on C.code_a=STC.code_a and C.code_b=STC.`code`
GROUP BY C.id