Joining of Multiple table - mysql

I have the following tables:
comitees [ID, Name, Total_Amount, Total_Members, Starting_Date, Ending_Date]
committee_group [Id, Name, Total_Members]
Group_Member [Id, Group_Id, Member_Name, Contribution]
I want to select Name from committee_group Where sum of Contribution from Group_Member is equal to Total_Amount from comitees
This is what I have so far
SELECT committee_group.*, Sum(Case When group_member.Group_Id='1'
THEN group_member.Contribution
ELSE 0 END)
FROM committee_group
LEFT JOIN group_member ON group_member.Id = committee_group.Id
LEFT join comitees ON group_member.Contribution = comitees.Total_Amount

This should work,
SELECT a.id,a.Name,a.Total_Members,c.Total_Amount
FROM committee_Group a
INNER JOIN (SELECT Name,sum(Contribution) as 'Sum_Con'
FROM Group_Member
GROUP BY Name)b on a.Id=b.Id
INNER JOIN comitees c on c.Total_Amount=b.Sum_Con
and b.Name=c.Name

Related

MySQL Group Join Table

I have below three SQL statement and I want to select out like below, I tried but not success.
Need some
help.
Output:
member_id, balance, firstname, lastname, LastPurchase, LastOrde
SELECT c.member_id
, c.firstname
, c.lastname
, m.balance
FROM member m
, customer c
where m.member_id = c.member_id
order
by m.member_id
SELECT member_id, max(date) as LastPurchase
FROM purchase
GROUP
BY member_id
SELECT member_id, max(date) as LastOrder
FROM ordert
GROUP
BY member_id
You can join these statements -
SELECT c.member_id, c.firstname, c.lastname, m.balance, p.LastPurchase, o.LastOrder
FROM member m
join customer c on m.member_id = c.member_id
left join (SELECT member_id, max(date) as LastPurchase
FROM purchase
GROUP BY member_id) p on p.member_id = m.member_id
left join (SELECT member_id, max(date) as LastOrder
FROM ordert
GROUP BY member_id) o on o.member_id = m.member_id
order by m.member_id
You can join the aggregate queries. The JOIN ... USING syntax comes handy here, since all join column names are the same:
SELECT c.member_id, c.firstname, c.lastname, m.balance, p.last_purchase, o.last_purchase
FROM member m
INNER JOIN customer c USING(member_id)
INNER JOIN (
SELECT member_id, max(date) last_purchase FROM purchase GROUP BY member_id
) p USING(member_id)
INNER JOIN (
SELECT member_id, max(date) last_order FROM order GROUP BY member_id
) o USING(member_id)
ORDER BY c.member_id
Important: your original query uses implicit, old-shool joins (with a comma in the from clause) - this syntax fell out of favor more than 20 years ago and its use is discourage, since it is harder to write, read, and understand.
One of the many benefits of using explicit joins here is that you can easily change the INNER JOINs to LEFT JOINs if there is a possibility that a member has no purchase or no order at all.

Stock Available Performance Mysql

I am trying to fetch the value of available stock in MYSQL but when the number of rows gets more than 35000 request is failing with no response. I use subqueries to fetch the value of the available stock.
Here is my code:
SELECT
p.`product-id` AS id,
p.`product-id` AS product_id,
ped.purchase_entry_id AS purchase_id,
p.`product-name` AS name,
m.name AS manufacturer,
p.`product-type` AS product_type,
ped.id AS batch_no,
ped.internal_sales_rate AS barcode,
c.name as category,
ped.size AS size,
IFNULL(ped.sales_rate,0) AS sales_rate,
IFNULL(ped.purchase_rate,0) AS purchase_rate,
IFNULL(SUM(ped.units),0) AS units_purchased,
(select IFNULL(SUM(sed.qty),0) FROM sales_entry_details sed WHERE (sed.batch_no = ped.id)) AS units_sold,
(select IFNULL(SUM(sr.qty),0) FROM sales_return_item sr WHERE (sr.batch_no = ped.id)) AS retured,
(select IFNULL(SUM(pri.qty),0) FROM purchase_return_items pri WHERE (pri.batch_no = ped.id)) AS purchase_return,
(select IFNULL(SUM(ast.qty),0) FROM adjustment_stock ast WHERE (ast.batch_no = ped.id)) AS adjustment,
(select IFNULL(SUM(ast2.batch_no),0) FROM adjustment_stock ast2 WHERE (ast2.batch_no = ped.id)) AS isChecked
FROM purchase_entry_details ped
LEFT JOIN products p on p.`product-id` = ped.product_id
LEFT JOIN category c ON c.id = p.`product-type`
LEFT JOIN manufacturer m ON m.id = p.manufacturer
GROUP BY ped.id;
Is there any better option to fetch the value of stock available in SQL??
The query looks fine. As there is no limiting criteria (no WHERE clause), you'll read the whole table sequentially.
You'd want indexes on batch_no in the involved tables of course. But I guess these are foreign keys to some batch table, so the indexes should already exist.
The only thing that I notice is that you select from adjustment_stock twice. You can avoid this by moving the subqueries to your FROM clause:
SELECT
p.`product-id` AS id,
p.`product-id` AS product_id,
ped.purchase_entry_id AS purchase_id,
p.`product-name` AS name,
m.name AS manufacturer,
p.`product-type` AS product_type,
ped.id AS batch_no,
ped.internal_sales_rate AS barcode,
c.name as category,
ped.size AS size,
IFNULL(ped.sales_rate,0) AS sales_rate,
IFNULL(ped.purchase_rate,0) AS purchase_rate,
IFNULL(SUM(ped.units),0) AS units_purchased,
IFNULL(sed.sum_qty),0) AS units_sold,
IFNULL(sr.sum_qty),0) AS retured,
IFNULL(pri.sum_qty),0) AS retured,
IFNULL(ast.sum_qty),0) AS adjustment,
IFNULL(ast.sum_batch_no),0) AS isChecked
FROM purchase_entry_details ped
LEFT JOIN products p on p.`product-id` = ped.product_id
LEFT JOIN category c ON c.id = p.`product-type`
LEFT JOIN manufacturer m ON m.id = p.manufacturer
LEFT JOIN
(
select batch_no, sum(qty) as sum_qty from sales_entry_details group by batch_no
) sed on sed.batch_no = ped.id
LEFT JOIN
(
select batch_no, sum(qty) as sum_qty from sales_return_item group by batch_no
) sr on sr.batch_no = ped.id
LEFT JOIN
(
select batch_no, sum(qty) as sum_qty from purchase_return_items group by batch_no
) pri on pri.batch_no = ped.id
LEFT JOIN
(
select batch_no, sum(qty) as sum_qty, sum(batch_no) as sum_batch_no
from adjustment_stock group by batch_no
) ast on ast.batch_no = ped.id
GROUP BY ped.id;
(Adding up batch numbers seems a bit weird, though.)
You can make separate joins for each table used in subqueries against purchase_entry_details table. In all these separate selects make group by ped.id. Afterwards make left join to new tables with sums.
SELECT
...
SED.sumqty,
SR.sumqty,
...
FROM purchase_entry_details ped
LEFT JOIN products p on p.`product-id` = ped.product_id
LEFT JOIN category c ON c.id = p.`product-type`
LEFT JOIN manufacturer m ON m.id = p.manufacturer
LEFT JOIN (
SELECT ped1.id, SUM(sed1.qty) as sumqty
FROM purchase_entry_details ped1
JOIN sales_entry_details sed1 ON sed1.batch_no = ped1.id
GROUP BY ped1.id
) SED ON SED.id = ped.id
LEFT JOIN (
SELECT ped1.id, SUM(sr1.qty) as sumqty
FROM purchase_entry_details ped1
JOIN sales_return_item sr1 ON sr1.batch_no = ped1.id
GROUP BY ped1.id
) SR ON SR.id = ped.id
...

mysql select multiple avg columns using where in condition and join query

how to use where in condition with this query? like, WHERE institutions.instituteId IN ("1","2","4","15").
SELECT (SELECT avg(rating_score.score) FROM reviews INNER JOIN rating_score ON reviews.reviewsId=rating_score.reviewsId WHERE reviews.instituteId='13' AND ratingItemId='1') as 'Acadamics',
(SELECT avg(rating_score.score) FROM reviews INNER JOIN rating_score ON reviews.reviewsId=rating_score.reviewsId WHERE reviews.instituteId='13' AND ratingItemId='2') as 'Area_of_study',
(SELECT avg(rating_score.score) FROM reviews INNER JOIN rating_score ON reviews.reviewsId=rating_score.reviewsId WHERE reviews.instituteId='13' AND ratingItemId='3') as 'Campus_Facilities',
(SELECT avg(rating_score.score) FROM reviews INNER JOIN rating_score ON reviews.reviewsId=rating_score.reviewsId WHERE reviews.instituteId='13' AND ratingItemId='4') as 'Acommadatoin',
(SELECT avg(rating_score.score) FROM reviews INNER JOIN rating_score ON reviews.reviewsId=rating_score.reviewsId WHERE reviews.instituteId='13' AND ratingItemId='5') as 'Sports_Facilities',
institutions.instituteId, institutions.instituteName, institutions.location, countries.countryName, institutions.siteAddress, institutions.overallRatings FROM institutions INNER JOIN countries ON institutions.countryId=countries.countryId
WHERE institutions.instituteId='13'
This is similar to the solutions in need to return two sets of data with two different where clauses but uses AVG instead of SUM. The main difference is that you don't use ELSE 0 in the CASE, because you don't want to average 0 for all the rows with a different raingItemId. AVG() will just ignore those null rows.
SELECT
AVG(CASE WHEN ratingItemId='1' THEN rs.score END) AS Academics,
AVG(CASE WHEN ratingItemId='2' THEN rs.score END) AS Area_of_study,
AVG(CASE WHEN ratingItemId='3' THEN rs.score END) AS Campus_Facilities,
AVG(CASE WHEN ratingItemId='4' THEN rs.score END) AS Acommadatoin,
AVG(CASE WHEN ratingItemId='5' THEN rs.score END) AS Sports_Facilities,
i.instituteName, i.location, c.countryName, i.siteAddress, i.overallRatings
FROM institutions AS i
INNER JOIN countries AS c ON i.countryId=c.countryId
LEFT JOIN reviews AS r ON r.instituteId = i.instituteId
LEFT JOIN rating_score AS rs ON rs.reviewsId = r.reviewsId
WHERE i.instituteId IN (1, 2, 4, 15)
GROUP BY i.instituteId

Select Row for Max Sum Value In Multiple Tables MYSQL

I need to query for the users with highest amount of sales by all projects, where the users are in users table, sales in units table, projects in projects table.
Projects Top Agent Total Sales for Project
Project A User A 100000
Project B User B 20000
Project C User A 1000
Project D - 0
The Projects column is list all the projects regardless it has sales or not.
The Top Agent column is list the user with the highest sales in the project.
The Total Sales for Project is the total sales for a projects.
The agent column i got is incorrect because there is someone else has the highest sales, the query seems to return the first row of the result
SELECT projects, pid, CASE WHEN agent is null THEN '-' ELSE agent END as agent,
CASE WHEN FORMAT(topagent,0) > 0 THEN FORMAT(topagent,0) ELSE 0 END as salesvolume
FROM (
SELECT projects.name as projects, projects.id as pid,
concat(users.f_name, ' ', users.l_name) as agent,
SUM(units.price) AS topagent
FROM users inner join bookings on bookings.agent_id = users.id
inner join units on bookings.unit = units.id
inner join types on types.id = units.types_id
inner join projects on projects.id = types.project_id
WHERE units.status = 'Sold'
GROUP BY pid
union
select projects.name as projects, projects.id as pid,
concat(users.f_name, ' ', users.l_name) as agent,
SUM(units.price) AS topagent
from projects left outer join types on projects.id = types.project_id
left outer join units on types.id = units.types_id and units.status = 'Sold'
left outer join bookings on units.id = bookings.unit and units.status = 'Sold'
left outer join users on bookings.agent_id = users.id and units.status = 'Sold'
group by pid
) a
GROUP BY pid
order by topagent desc
Try it if helps you-
SELECT a.prjname, IFNULL(usr.name,'-') AS Top_Agent, SUM(a.sale) AS Total_Sales_for_Project
FROM
(
SELECT prj.id AS prjid,prj.name AS prjname,usr.id,usr.name AS usrname,IFNULL(SUM(unit.price),0) AS sale
FROM projects AS prj
LEFT JOIN `types` AS typ ON typ.project_id=prj.id
LEFT JOIN units AS unt ON unt.type_id=typ.id AND unt.status='sold'
LEFT JOIN bookings bkg ON bkg.unit=unt.id
LEFT JOIN users usr ON usr.id=bkg.agent_it
GROUP BY prj.id,usr.id
ORDER BY prj.id,usr.id,sale DESC
) a
GROUP BY a.prjid
Your column aliases are confusing to read. In English, it seems what you mean by topagent is "sum of sales by a human". But in SQL, your GROUP BY pid means that the SUM(units.price) really means "sum of sales in a project".
Then the UNION adds a list of projects to a list of users. The agent names are basically random at this point.
If I decipher the requirements as "a list of projects ranked by the sales values of each project's top sales agent", then you'd have SQL as below:
SELECT
pid,
projects.name as project_name,
IFNULL(a.top_agent_name,'-') as top_agent_name,
CASE WHEN FORMAT(top_agent_sales,0) > 0 THEN FORMAT(top_agent_sales,0) ELSE 0 END as top_agent_salesvolume
FROM
projects
JOIN
SELECT
a.pid,
a.agent_name as top_agent_name,
a.agent_sales as top_agent_sales
FROM
(SELECT
projects.id as pid,
concat(users.f_name, ' ', users.l_name) as agent_name,
SUM(units.price) AS agent_sales
FROM users
inner join bookings on bookings.agent_id = users.id
inner join units on bookings.unit = units.id
inner join types on types.id = units.types_id
inner join projects on projects.id = types.project_id
WHERE units.status = 'Sold'
GROUP BY pid, users.id
) a # get all agents for all projects
JOIN
(SELECT
MAX(agent_sales) as max_project_agent_sales
FROM
(SELECT
projects.id as pid,
SUM(units.price) AS agent_sales
FROM users
inner join bookings on bookings.agent_id = users.id
inner join units on bookings.unit = units.id
inner join types on types.id = units.types_id
inner join projects on projects.id = types.project_id
WHERE units.status = 'Sold'
GROUP BY pid, users.id
)
GROUP BY pid) b ON a.pid = b.pid
WHERE
a.agent_sales = b.max_project_agent_sales
ORDER BY a.agent_sales desc
Old answer below:
There are 2 topagents for each pid in the inner query since it's a union of 2 group bys. There isn't a reducing function in the outer group by pid so the topagent returned in the select is the first one that came up in the inner query.

Using count for two different values in the same table

In the following query I am trying to fetch data from tables: company, classes_by_company, and person. I have a foreign key in all tables with the name company_id. In the classes_by_company table a class can have a class_status that can be either active or inactive. The same goes for table person with its corresponding person_status. I am able to count the total number of classes and the total number of persons, find the working query here: SQFIDDLE. In the query below I am trying to incorporate the previous query but now also count the total number of class_status=ACTIVE and person_status=ACTIVE. I am getting error Not unique table/alias: 'c'. How can I can count the total number and the total number of active classes and person? SQLFIDDLE
SELECT a.id, a.company_id, a.status, c.class_status, p.person_status,
c.total_count AS classes_per_company,
p.total_count AS employees_per_company,
c.active_count AS active_classes,
p.active_count AS active_instructors
FROM company a
LEFT JOIN (SELECT company_id, COUNT(*) as total_count
FROM classes_by_company
GROUP BY company_id) c
ON a.company_id = c.company_id
LEFT JOIN (SELECT company_id, COUNT(*) as active_count
FROM classes_by_company
WHERE class_status = 'ACTIVE'
GROUP BY company_id) c
ON a.company_id = c.company_id
LEFT JOIN (SELECT company_id, COUNT(*) as total_count
FROM person
GROUP BY company_id) p
ON a.company_id = p.company_id
LEFT JOIN (SELECT company_id, COUNT(*) as active_count
FROM person
WHERE person_status = 'ACTIVE'
GROUP BY company_id) p
ON a.company_id = c.company_id
Table Structure:
CREATE TABLE company
(
id int auto_increment primary key,
company_id int,
status varchar(20)
);
CREATE TABLE classes_by_company
(
id int auto_increment primary key,
company_id int,
class_name varchar(20),
class_status varchar(20)
);
CREATE TABLE person
(
id int auto_increment primary key,
employee_id int,
company_id int,
person_name varchar(20),
person_status varchar(20)
);
Your query structure is fine, you just need to give different aliases to each subquery that you join with.
You also failed to return class_status and person_status from the c and p subqueries.
SELECT a.id, a.company_id, a.status, c.class_status, p.person_status,
c.total_count AS classes_per_company,
p.total_count AS employees_per_company,
ca.active_count AS active_classes,
pa.active_count AS active_instructors
FROM company a
LEFT JOIN (SELECT company_id, class_status, COUNT(*) as total_count
FROM classes_by_company
GROUP BY company_id) c
ON a.company_id = c.company_id
LEFT JOIN (SELECT company_id, COUNT(*) as active_count
FROM classes_by_company
WHERE class_status = 'ACTIVE'
GROUP BY company_id) ca
ON a.company_id = ca.company_id
LEFT JOIN (SELECT company_id, person_status, COUNT(*) as total_count
FROM person
GROUP BY company_id) p
ON a.company_id = p.company_id
LEFT JOIN (SELECT company_id, COUNT(*) as active_count
FROM person
WHERE person_status = 'ACTIVE'
GROUP BY company_id) pa
ON a.company_id = pa.company_id
I changed the aliases to ca for active classes, and pa for active person.
SQLFIDDLE
You can also reduce the number of joins by counting the active rows in the same query as the total rows:
SELECT a.id, a.company_id, a.status, c.class_status, p.person_status,
c.total_count AS classes_per_company,
p.total_count AS employees_per_company,
c.active_count AS active_classes,
p.active_count AS active_instructors
FROM company a
LEFT JOIN (SELECT company_id, class_status, COUNT(*) as total_count, SUM(class_status = 'ACTIVE') as active_count
FROM classes_by_company
GROUP BY company_id) c
ON a.company_id = c.company_id
LEFT JOIN (SELECT company_id, person_status, COUNT(*) as total_count, SUM(person_status = 'ACTIVE') as active_count
FROM person
GROUP BY company_id) p
ON a.company_id = p.company_id
SQLFIDDLE
Very small change...table alias's (or subqueries) cannot be the same
SELECT a.id, a.company_id, a.status, c.class_status, p.person_status,
c.total_count AS classes_per_company,
p.total_count AS employees_per_company,
ca.active_count AS active_classes,
pa.active_count AS active_instructors
FROM company a
LEFT JOIN (SELECT company_id, COUNT(*) as total_count
FROM classes_by_company
GROUP BY company_id) c
ON a.company_id = c.company_id
LEFT JOIN (SELECT company_id, COUNT(*) as active_count
FROM classes_by_company
WHERE class_status = 'ACTIVE'
GROUP BY company_id) ca
ON a.company_id = c.company_id
LEFT JOIN (SELECT company_id, COUNT(*) as total_count
FROM person
GROUP BY company_id) p
ON a.company_id = p.company_id
LEFT JOIN (SELECT company_id, COUNT(*) as active_count
FROM person
WHERE person_status = 'ACTIVE'
GROUP BY company_id) pa
ON a.company_id = c.company_id