I have written a query which output the sale figures of all employees, and their name and what shop they work at. But I am trying to find the top sales person for each shop. Can you please explain how can i only show the top sales person for each shop. I was thinking that i can use
SELECT empname, shopname, SUM( rentalrate ) AS Sales
FROM frs_FilmRental
NATURAL JOIN frs_Employee
NATURAL JOIN frs_Shop
GROUP BY empnin, shopname
Here is screenshot of my
Results so far
Here is a really ugly way:
SELECT t1.empname,
t1.shopname,
t2.maxsales
FROM
(
SELECT empname, shopname, SUM(rentalrate) AS sales
FROM frs_FilmRental
NATURAL JOIN frs_Employee
NATURAL JOIN frs_Shop
GROUP BY empname, shopname
) t1
INNER JOIN
(
SELECT t.shopname, MAX(t.Sales) AS maxsales
FROM
(
SELECT shopname, SUM(rentalrate) AS Sales
FROM frs_FilmRental
NATURAL JOIN frs_Employee
NATURAL JOIN frs_Shop
GROUP BY empname, shopname
) t
GROUP BY t.shopname
) t2
ON t1.shopname = t2.shopname AND
t1.sales = t2.maxsales
You will recognize the subquery t1 as simply being your original query. The t2 subquery restricts this result set to only those shops which had the highest sales, implying only the record corresponding to the employeee with the highest sales. In the event of a tie, both records would be returned for that shop.
The query is a bit verbose, but this owes in part to that MySQL does not have support for row number or common table expressions.
SELECT *
FROM
(
SELECT DISTINCT empname, shopname,
SUM( rentalrate ) OVER (PARTITION BY shopname,empname ) AS Sales,
ROW_NUMBER OVER (PARTITION BY shopname,empname ) AS RN
FROM frs_FilmRental
NATURAL JOIN frs_Employee
NATURAL JOIN frs_Shop
GROUP BY empnin, shopname
) X
WHERE X.RN=1
Related
How to i get the top vendor for each country? I have this code and it shows the connection between the two tables, now I have to get the largest gmv per country.
Here is my working code:
SELECT DISTINCT a.country_name, b.vendor_name,
SUM(a.gmv_local) as total_gmw
from `my-project-67287.order1.order2`a
join `my-project-67287.vendor1.vendor2` b on a.vendor_id = b.id
group by a.country_name, b.vendor_name;
The top 3 should show this:
Assuming you can save that SELECT into a table called vendors, you need to use it as the subquery in the FROM clause.
You could use this:
SELECT vendors.country_name, vendors.vendor_name, MAX(vendors.total_gmw)
FROM
(
SELECT DISTINCT a.country_name, b.vendor_name,
SUM(a.gmv_local) as total_gmw
from `my-project-67287.order1.order2`a
join `my-project-67287.vendor1.vendor2` b on a.vendor_id = b.id
group by a.country_name, b.vendor_name
) AS vendors
GROUP BY vendors.country_name;
I must mention I have not tested your query, since I do not have your tables, so I assumed it's correct.
I only created the vendors table with the required fields and values from your picture. This should print:
SELECT odr.c_name,vdr.v_name,odr.gmv
FROM(
SELECT *
FROM(
SELECT c_name,v_id,gmv
FROM `order`
ORDER BY gmv DESC
)
GROUP BY c_name
)AS odr
LEFT JOIN vender AS vdr ON vdr.id = odr.v_id
GROUP BY odr.c_name
c_name short for country_name
have this problem for a school example problem where I have to get the total salary for coaches and participants in March (done below) and then I have to sum to get the total salary due in March for all employees which I just want to add onto the end of the Total Salary column.
This is what I have so far:
(SELECT Coach.name AS Name, COUNT(*) AS 'Shows Attended In March',
dailySalary AS 'Daily Salary', sum(dailySalary) AS 'Total Salary'
FROM Coach, TVShow, CoachInShow
WHERE monthname(dateOfShow)='March' AND
Coach.idCoach=CoachInShow.idCoach AND TVShow.idShow =
CoachInShow.idShow
GROUP BY Coach.name, Coach.dailySalary)
UNION
(SELECT Participant.name AS Name, COUNT(*) AS 'Shows Attended In
March', dailySalary AS 'Daily Salary', sum(dailySalary) AS 'Total
Salary'
FROM Participant, TVShow, Contender, ContenderInShow
WHERE monthname(dateOfShow)='March' AND Participant.idContender =
Contender.idContender AND Contender.idContender =
ContenderInShow.idContender AND ContenderInShow.idShow = TVShow.idShow
GROUP BY Participant.name, Participant.dailySalary);
I tried using GROUP BY WITH ROLLBACK on the whole thing but it doesn't add up only the TotalSalary columns. I've spent a while on this and kinda stumped.
I pasted the data here for what I'm working with: https://www.db-fiddle.com/f/gPKVQrZCMkvHUqViAUzCqZ/0 http://sqlfiddle.com/#!9/535f6d/1
Put the UNION into a subquery. In the main query, sum all the counts and total salaries, and use WITH ROLLUP to get the grand total.
You don't need dailySalary in the GROUP BY clause, since it's functionally dependent on the ID.
SELECT name AS Name, SUM(count) AS `Shows Attended in March`, SUM(totalSalary) AS `Total Salary`
FROM (
SELECT Coach.name, COUNT(*) AS count, SUM(dailySalary) AS totalSalary
FROM Coach
JOIN CoachInShow ON Coach.idCoach=CoachInShow.idCoach
JOIN TVShow ON TVShow.idShow = CoachInShow.idShow
WHERE monthname(dateOfShow)='March'
GROUP BY Coach.idCoach
UNION
SELECT Participant.name, COUNT(*) AS count, SUM(dailySalary) AS totalSalary
FROM Participant
JOIN Contender ON Participant.idContender = Contender.idContender
JOIN ContenderInShow ON Contender.idContender = ContenderInShow.idContender
JOIN TVShow ON ContenderInShow.idShow = TVShow.idShow
WHERE monthname(dateOfShow)='March'
GROUP BY Participant.idParticipant
) AS x
GROUP BY Name
WITH ROLLUP
DEMO
I want to get the customer who mostly borrowed films of category 3 in 2016, July
SELECT c_firstName, c_lastName, rental.c_ID
FROM customer, rental
GROUP BY rental.c_ID HAVING rental.c_ID=MAX((SELECT COUNT(rental.c_ID)
FROM customer, copies, rentalprocess, rental, film
WHERE customer.c_ID=rental.c_ID AND rentalprocess.r_ID=rental.r_ID AND
rentalprocess.s_ID=copies.s_ID AND film.f_ID=copies.f_ID AND
f_category=3 AND r_date LIKE "2016-07%" GROUP BY rental.c_ID))
But ir doesn't work because it said that the subquery returns more than one row
What can I do?
Max() is an aggregate function that needs to be in a select statement
SELECT
c_firstName
, c_lastName
, rental.c_ID
FROM customer, rental
GROUP BY rental.c_ID
HAVING rental.c_ID=
(
select
MAX(i.iID)
from
(
SELECT
COUNT(rental.c_ID) iID
FROM customer, copies, rentalprocess, rental, film
WHERE
customer.c_ID=rental.c_ID AND
rentalprocess.r_ID=rental.r_ID AND
rentalprocess.s_ID=copies.s_ID AND
film.f_ID=copies.f_ID AND
f_category=3
AND r_date LIKE "2016-07%"
GROUP BY rental.c_ID
) i
)
In this case the sub-select returns multiple rows but then you take the max value of that query
Comment from Mr Linoff is correct, you should use explicity joins:
SELECT
c_firstName
, c_lastName
, rental.c_ID
FROM customer, rental
GROUP BY rental.c_ID
HAVING rental.c_ID=
(
select
MAX(i.iID)
from
(
SELECT
COUNT(rental.c_ID) iID
FROM
customer
inner join rental
on customer.c_ID=rental.c_ID
inner join rentalprocess
on rentalprocess.r_ID=rental.r_ID
inner join copies
on rentalprocess.s_ID=copies.s_ID
inner join film on film.f_ID=copies.f_ID
WHERE
f_category=3
AND r_date LIKE "2016-07%"
GROUP BY rental.c_ID
) i
)
your code should look something like this, join the tables properly in the code.
I dont know wich columns and table would suit best for the solution becuse I dont got your full schema. but this should give faster query. Put more columns in the select if you wish.
select c_firstName | ' ' | c_lastName, count(rental.c_ID) as rentalCustomer
from customer
inner join rental
on join " connect the both tables"
innner join rentalprocess
on "connect rental with rentalprocess"
inner join copies
on " connect rentalprocess with copies"
inner join film
on "connect copies with film"
WHERE customer.c_ID=rental.c_ID AND
rentalprocess.r_ID=rental.r_ID AND
rentalprocess.s_ID=copies.s_ID AND
film.f_ID=copies.f_ID AND
f_category=3 AND r_date LIKE "2016-07%"
group by c_firstName, c_lastName, rental.c_ID
order by rental.c_ID desc;
I just edit my old code and try to make nice complex query.
My query looks like:
SELECT axnmrs_cases.claimnumber as claim, axnmrs_cases.vin as vin, axnmrs_cases.date_created as date, axnmrs_calculations.totalcosts as totalcosts, axnmrs_cases.country as country
FROM axnmrs_cases
INNER JOIN axnmrs_calculations ON ( axnmrs_cases.case_id = axnmrs_calculations.case_id
AND axnmrs_cases.country = axnmrs_calculations.country )
WHERE vin = :vin
This works and display results, whats perfect (even I can't belieave it :D), however I need just last calculation not all of them.
INNER JOIN axnmrs_calculations ON ( axnmrs_cases.case_id = axnmrs_calculations.case_id
AND axnmrs_cases.country = axnmrs_calculations.country ) ORDER BY axnmrs_calculations.calculation_id DESC LIMIT 1
However I'm not sure how to limit just INNER JOIN not the whole query, can someone advise me please?
Thanks
If you want the last calculation per case_id and country, then you need to create a derived table (subquery in the from clause) that gets you these and you join the cases and calculations table on this derived table.
You need to have either an auto increment id in the calculations table or a timestamp, or a flag that identifies the last version of the calculations. I'll assume, that you have an autoincrement id field in the calculations table:
SELECT axnmrs_cases.claimnumber as claim, axnmrs_cases.vin as vin, axnmrs_cases.date_created as date, axnmrs_calculations.totalcosts as totalcosts, axnmrs_cases.country as country
FROM axnmrs_cases
INNER JOIN axnmrs_calculations AS ac ON ( axnmrs_cases.case_id = ac.case_id AND axnmrs_cases.country = ac.country )
INNER JOIN (SELECT MAX(id) AS maxid, case_id, country FROM axnmrs_calculations GROUP BY case_id, country) AS T
ON ac.id=T.maxid and ac.case_idóT.case_id and ac.country=T.country
WHERE vin = :vin
I have two tables (listed only fields important for the question):
t_groups
INT groupId PRIMARY
VARCHAR(255) grname
t_goods
INT goodId PRIMARY
INT groupId
INT price
VARCHAR(255) name
Now I need a query, which selects group names and name of the cheapest good in each group. Tried doing it this way:
SELECT gr.groupId, grname, g.name
FROM t_groups AS gr
LEFT JOIN (SELECT * FROM t_goods ORDER BY PRICE ASC LIMIT 1) AS g
ON g.groupId = gr.groupId
but it doesn't work — returns NULLs in g.name field. It could be easily explained:
SELECT within JOIN statement selects cheapest good first, and then tries to "filter it" by groupId. Obviously, it'll only work for the group cheapest good belongs to.
How do I solve the task?
Why your query does not work
SELECT gr.groupId, grname, g.name
FROM t_groups AS gr
LEFT JOIN (SELECT * FROM t_goods ORDER BY PRICE ASC LIMIT 1) AS g
ON g.groupId = gr.groupId
The inner query selects the absolutely cheapest good (irrespective of group) in your database. Therefore, when you LEFT JOIN the groups to this result set, only the group which actually includes the universally cheapest good has a matching row (that group should get the g.name column filled properly). However, due to the way LEFT JOIN works all other groups will get NULL as the value of all columns in g.
The correct solution
First, you need to select the cheapest price in each group. This is easy:
SELECT groupId, MIN(price) AS minPrice FROM t_goods GROUP BY (groupId)
However the cheapest price is not useful without the associated goodId. The problem is that it's not meaningful to write something like:
/* does not make sense, although MySql has historically allowed it */
SELECT goodId, groupId, MIN(price) AS minPrice FROM t_goods GROUP BY (groupId)
The reason is that you cannot select a non-grouped column (i.e. goodId) unless you wrap it in an aggregate function (such as MIN): we don't know which goodId you want from among those that share the same groupId.
The correct, portable way to get the goodId of the cheapest goods in each group is
SELECT goodId, temp.groupId, temp.minPrice
FROM (SELECT groupId, MIN(price) AS minPrice FROM t_goods GROUP BY groupId) temp
JOIN t_goods ON temp.groupId = t_goods.groupId AND temp.minPrice = t_goods.price)
The above query first finds out the cheapest price per group, and then joins to the goods table again to find the goodIds of the goods having that price inside that group.
Important: if multiple goods have an equal cheapest price in a group, this query will return all of them. If you only want one result per group you have to specify the tiebreaker, for example:
SELECT MIN(goodId), temp.groupId, MIN(temp.minPrice)
FROM (SELECT groupId, MIN(price) AS minPrice FROM t_goods GROUP BY groupId) temp
JOIN t_goods ON temp.groupId = t_goods.groupId AND temp.minPrice = t_goods.price)
GROUP BY temp.groupId
With this query in hand, you can then find the name and price of the single cheapest good in each group (lowest goodId will be used as tiebreaker):
SELECT groupId, grname, gd.name, t3.minPrice
FROM t_groups AS gr
LEFT JOIN (SELECT MIN(goodId) AS goodId, t1.groupId, MIN(t1.minPrice) AS minPrice
FROM (SELECT groupId, MIN(price) AS minPrice FROM t_goods GROUP BY groupId) t1
JOIN t_goods ON t1.groupId = t_goods.groupId AND t1.minPrice = t_goods.price
) t2
) t3 ON gr.groupId = t3.groupId
LEFT JOIN t_goods gd ON t3.goodId = gd.goodId
This final query performs two joins at its "outer" level:
joins groups with the "goodId and cheapest price for each group" table to get the goodId and cheapest price
then joins with the goods table to get the name of the good with this goodId
It will produce only one good per group, even if multiple goods are tied for cheapest.
Here's how you could do it:
select
t_groups.grname as `name of group`,
t_goods.name as `name of good`
from (
select
groupId,
min(price) as min_price
from t_goods
group by groupId
) as mins
inner join t_goods
on mins.groupId = t_goods.groupId and mins.min_price = t_goods.price
inner join t_groups
on mins.groupId = t_groups.groupId
How this works:
mins subquery gets the minimum price for each groupId
joining mins to t_goods pulls all of the goods out that have the minimum price in their group. Note that this could return multiple goods in a single group, if there are multiple goods with the minimum price
that's then joined to t_groups to get the group name
Your query was presumably returning NULLs because it was left joining to a subquery with only one row.