I have this table
dept | amount | price
1 | 2 | 20
3 | 2 | 50
4 | 3 | 10
2 | 5 | 20
1 | 1 | 15
4 | 1 | 30
4 | 6 | 5
2 | 7 | 7
1 | 1 | 24
2 | 5 | 12
dept is de department number
amount is how many of a product is sold.
price is how much the price of the product is
How can I found the dept, that has got the most money from selling their products.
I have this:
SELECT dept, SUM( amount * price ) AS total
FROM table
GROUP BY dept
I need it to return the dept with the highest total.
I can't use MAX( SUM( amount * price ) ), so how do I do this?
Oh yeah. It's a school assignment and I may not use LIMIT or ORDER BY
Without using LIMIT you can try using HAVING:
SELECT dept,SUM(amount * price) AS total
FROM tab1
GROUP BY dept
HAVING SUM(amount * price) = (
SELECT MAX(total)
FROM (
SELECT SUM(amount * price) AS total
FROM tab1
GROUP BY dept
) a
)
sqlfiddle demo
If you do not want to use ORDER and LIMIT. This is a solution ( Tested)
SELECT dept, SUM( amount * price ) AS total
FROM table
GROUP BY dept
HAVING SUM( amount * price ) = ( SELECT MAX(A.total)
FROM
(
SELECT dept, SUM( amount * price ) AS total
FROM table
GROUP BY dept
) A
)
This will give you the department with the highest total:
select top 1 dept, sum(amount * price)
from table
group by dept
order by sum(amount * price) desc
You can sort by the total descending and take the first entry
SELECT dept, SUM( amount * price ) AS total
FROM table
GROUP BY dept
order by total desc
limit 1
Related
Let's assume there are two different tables:
PACKAGE
id
--
1
2
3
PRODUCT
id | package_id | currency | total
----------------------------------
1 | 1 | USD | 100
2 | 1 | EUR | 200
3 | 2 | USD | 300
4 | 2 | USD | 400
5 | 3 | GBP | 500
And the desired result is to get concatenated total amounts for each package (from its products) by each DISTINCT currency, something like:
id | total_amount
----------------------
1 | USD 100, EUR 200
2 | USD 700
3 | GBP 500
Tried with this query:
SELECT
packages.id,
(
SELECT
GROUP_CONCAT(CONCAT(currency,' ',total))
FROM
(
SELECT
products.currency AS currency,
SUM(products.total) AS total
FROM products
WHERE products.package_id = [[ packages.id ]] -- double brackets just for marking
GROUP BY products.currency
) T
) AS total_amount
FROM packages
LEFT JOIN products
ON products.package_id = packages.id
GROUP BY packages.id;
But there is an error that package.id (in double brackets above) is not visible, probably because of the subquery depth.
Is there any way that it can be achieved? Thanks.
You may try rewriting your query as a left join instead of a subquery which may be more efficient or faster as shown below:
SELECT
p.id,
ct.currency_totals
FROM
packages p
LEFT JOIN (
SELECT
package_id,
GROUP_CONCAT(
CONCAT(currency,' ',total)
) as currency_totals
FROM (
SELECT
package_id,
currency,
SUM(total) as total
FROM
products
GROUP BY
package_id,
currency
) t
GROUP BY
package_id
) ct on ct.package_id=p.id;
id
currency_totals
1
USD 100,EUR 200
2
USD 700
3
GBP 500
Moreover, if you only require the package id of currently used packages and no other details , using your subquery may be enough for this task.
SELECT
package_id,
GROUP_CONCAT(
CONCAT(currency,' ',total)
) as currency_totals
FROM (
SELECT
package_id,
currency,
SUM(total) as total
FROM
products
GROUP BY
package_id,
currency
) t
GROUP BY
package_id;
package_id
currency_totals
1
USD 100,EUR 200
2
USD 700
3
GBP 500
View working demo on DB Fiddle
you can use :
select package_id , group_concat(concat(currency,' ',grandtotal))
from (
select package_id,currency, sum(total) grandtotal
from products
group by package_id,currency
) t group by package_id
db<>fiddle here
Try use alias for tables names to identify...
SELECT
pkg.id,
(
SELECT
GROUP_CONCAT(CONCAT(currency,' ',total))
FROM
(
SELECT
products.currency AS currency,
SUM(products.total) AS total
FROM products
WHERE products.package_id = pkg.id
GROUP BY products.currency
) T
) AS total_amount
FROM packages as pkg
LEFT JOIN products
ON products.package_id = pkg.id
GROUP BY pkg.id;
I'm looking to report the best seller by total sales price using the table below:
Sales table:
seller_id | quantity | price
| 1 | 2 | 2000 |
| 1 | 1 | 800 |
| 2 | 1 | 800 |
| 3 2 | 2800 |
The result need to be 1 & 3 (a table with 1 column "seller_id")since both sellers with id 1 and 3 sold products with the most total price of 2800
I tried to write a query using rank.. in a subquery, I will have something like:
SELECT
sum(price), rank() over (order by price desc )
FROM
sales
group by seller_id
Then, I need to select the sum(price) with rank=1, but I don't know how to write that..
Then, outside of the subquery, I want to select just the seller_id.
How do we do these?
Use RANKING function for retrieving seller_id based on highest price. RANK() function serialize the position with a GAP. If two values in same position then third value position after this to value will 3 not 2.
-- MySQL (v5.8)
SELECT t.seller_id, t.total_price
FROM (SELECT seller_id, SUM(price) total_price
, RANK() OVER (ORDER BY SUM(price) DESC) rank_price
FROM sales
GROUP BY seller_id) t
WHERE t.rank_price = 1
DENSE_RANK() function serialize the position without a GAP. If top 5 price needed in future then it'll better.
-- MySQL (v5.8)
SELECT t.seller_id, t.total_price
FROM (SELECT seller_id, SUM(price) total_price
, DENSE_RANK() OVER (ORDER BY SUM(price) DESC) rank_price
FROM sales
GROUP BY seller_id) t
WHERE t.rank_price = 1
Please check from url https://dbfiddle.uk/?rdbms=mysql_8.0&fiddle=90c756fa6d3ab25914721cfe40df5e9a
I need to to get the max price of the 33% cheapests products. My idea is like this. Of course, this code is just an example. I need to use subqueries.
select max((select price from products order by preco limit 33% )) as result from products
For example
product_id price
1 10
2 50
3 100
4 400
5 900
6 8999
I need I query that returns 50, since 33% of the rows are 2, and the max value of the 2(33%) of the rows is 50.
In MySQL 8+, you would use window functions:
select avg(precio)
from (select p.*, row_number() over (order by precio) as seqnum,
count(*) over () as cnt
from products p
) p
where seqnum <= 0.33 * cnt;
Obviously there are multiple approaches to this but here is how I would do it.
Simply get a count on the table. This will let me pick the max price of the cheapest 33% of products. Let's say it returned n records. Third of that would be n/3. Here you can either round up or down but needs to be rounded in case of a fraction.
Then my query would be something like SELECT * FROM products ORDER BY price ASC LIMIT 1 OFFSET n/3. This would return me a single record with minimal calculations and look ups on MySQL side.
For MySQL versions under MySQL 8.0 you can use MySQL's user variables to simulate/emulate a ROW_NUMBER()
Query
SELECT
t.product_id
, t.price
, (#ROW_NUMBER := #ROW_NUMBER + 1) AS ROW_NUMBER
FROM
t
CROSS JOIN (SELECT #ROW_NUMBER := 0) AS init_user_variable
ORDER BY
t.price ASC
Result
| product_id | price | ROW_NUMBER |
| ---------- | ----- | ---------- |
| 1 | 10 | 1 |
| 2 | 50 | 2 |
| 3 | 100 | 3 |
| 4 | 400 | 4 |
| 5 | 900 | 5 |
| 6 | 8999 | 6 |
When we get the ROW_NUMBER we can use that in combination with ROW_NUMBER <= CEIL(((SELECT COUNT(*) FROM t) * 0.33));
Which works like this
(SELECT COUNT(*) FROM t) => Counts and returns 6
(SELECT COUNT(*) FROM t) * 0.33) Calculates 33% from 6 which is 1.98 and returns it
CEIL(..) Return the smallest integer value that is greater than or equal to 1.98 which is 2 in this case
ROW_NUMBER <= 2 So the last filter is this.
Query
SELECT
a.product_id
, a.price
FROM (
SELECT
t.product_id
, t.price
, (#ROW_NUMBER := #ROW_NUMBER + 1) AS ROW_NUMBER
FROM
t
CROSS JOIN (SELECT #ROW_NUMBER := 0) AS init_user_variable
ORDER BY
t.price ASC
) AS a
WHERE
ROW_NUMBER <= CEIL(((SELECT COUNT(*) FROM t) * 0.33));
Result
| product_id | price |
| ---------- | ----- |
| 1 | 10 |
| 2 | 50 |
see demo
To get get the max it's just as simple as adding ORDER BY a.price DESC LIMIT 1
Query
SELECT
a.product_id
, a.price
FROM (
SELECT
t.product_id
, t.price
, (#ROW_NUMBER := #ROW_NUMBER + 1) AS ROW_NUMBER
FROM
t
CROSS JOIN (SELECT #ROW_NUMBER := 0) AS init_user_variable
ORDER BY
t.price ASC
) AS a
WHERE
ROW_NUMBER <= CEIL(((SELECT COUNT(*) FROM t) * 0.33))
ORDER BY
a.price DESC
LIMIT 1;
Result
| product_id | price |
| ---------- | ----- |
| 2 | 50 |
see demo
If your version supports window functions, you can use NTILE(3) to divide the rows into three groups ordered by price. The first group will contain (about) "33%" of lowest prices. Then you just need to select the MAX value from that group:
with cte as (
select price, ntile(3) over (order by price) as ntl
from products
)
select max(price)
from cte
where ntl = 1
Demo
Prior to MySQL 8.0 I would use a temprary table with an AUTO_INCREMENT column:
create temporary table tmp (
rn int auto_increment primary key,
price decimal(10,2)
);
insert into tmp(price)
select price from products order by price;
set #max_rn = (select max(rn) from tmp);
select price
from tmp
where rn <= #max_rn / 3
order by rn desc
limit 1;
Demo
I have the current table:
+----------+-------+
| salesman | sales |
+----------+-------+
| 1 | 142 |
| 2 | 120 |
| 3 | 176 |
| 4 | 140 |
| 5 | 113 |
| 6 | 137 |
| 7 | 152 |
+----------+-------+
I would like to make a query to retrieve the 3 top salesman, and an "Other" column, that would be the sum of everyone else. The expected output would be:
+----------+-------+
| salesman | sales |
+----------+-------+
| 3 | 176 |
| 7 | 152 |
| 1 | 142 |
| Others | 510 |
+----------+-------+
I am using MySQL, and I am experienced about it, but i can't imagine a way of doing this kind of GROUP BY.
A tried UNION with 2 SELECT, one for the top 3 salesman and another select for the "Others", but I couldn't figure a way of excluding the top 3 from the 2nd SELECT
You can do this by LEFT JOINing your table to a list of the top 3 salesmen, and then grouping on the COALESCEd salesman number from the top 3 table (which will be NULL if the salesman is not in the top 3).
SELECT COALESCE(top.sman, 'Others') AS saleman,
SUM(sales) AS sales
FROM test
LEFT JOIN (SELECT salesman AS sman
FROM test
ORDER BY sales DESC
LIMIT 3) top ON top.sman = test.salesman
GROUP BY saleman
ORDER BY saleman = 'Others', sales DESC
Output:
saleman sales
3 176
7 152
1 142
Others 510
Demo on dbfiddle
Using UNION, ORDER BY, LIMIT, OFFSET AND GROUP BY statements you should do the trick:
SELECT salesman, sales
FROM t
ORDER BY sales DESC LIMIT 3
UNION
SELECT 'Others', SUM(sales)
FROM (SELECT salesman, sales
FROM t
ORDER BY sales DESC LIMIT 3, 18446744073709551615) AS tt;
The big number at the end is the way to apply limit until the end of the table, as suggested here
This is a pain in MySQL:
(select salesman, count(*) as cnt
from t
group by salesman
order by count(*), salesman
limit 3
) union all
(select 'Others', count(*)
from t left join
(select salesman, count(*) as cnt
from t
group by salesman
order by count(*)
limit 3
) t3
on t3.salesman = t.salesman
where t3.salesman is null
);
This should be the fastest one if appropriate indexes are present:
(
SELECT salesman, sales
FROM t
ORDER BY sales DESC
LIMIT 3
)
UNION ALL
(
SELECT 'Other', SUM(sales) - (
SELECT SUM(sales)
FROM (
SELECT sales
FROM t
ORDER BY sales DESC
LIMIT 3
) AS top3
)
FROM t
)
ORDER BY CASE WHEN salesman = 'Other' THEN NULL ELSE sales END DESC
this will work:
select salesman,sales from tablename a where a.salesman in (3,7,1)
union all
select 'others' as others,sum(a.sales) as sum_of_others from tablename a where
a.salesman not in (3,7,1) group by others;
check https://www.db-fiddle.com/f/73GjFXL3KsZsYnN26g3rS2/0
I have the below 2 MYSQL weekly tables:
TableA_Wk1
Id | Price
----------
1 | 1
1 | 2
2 | 5
TableA_Wk2
Id | Price
----------
1 | 2
4 | 2
I can group the price in one table:
SELECT Id, SUM(Price) FROM TableA_Wk1
GROUP BY Id
and get
Id | Price
----------
1 | 3
2 | 5
I would like to also consider the table TableA_Wk2 to get the below:
Id | Price
----------
1 | 5
2 | 5
4 | 2
If i use UNION ALL the result is separated:
SELECT Id, SUM(Price) FROM TableA_Wk1
GROUP BY Id
UNION ALL
SELECT Id, SUM(Price) FROM TableA_Wk2
GROUP BY Id
First get all the <Id,price> tuples from those two tables. Then Use SUM and GROUP BY Id on the resultant table.
SELECT
t.Id,
SUM(t.price)
FROM
(
SELECT Id, Price FROM TableA_Wk1
UNION ALL
SELECT Id, Price FROM TableA_Wk2
) AS t
GROUP BY t.Id
Note
UNION removes duplicates.
UNION ALL doesn't.
First UNION , then GROUP BY :
SELECT t.id,sum(t.price) as price
FROM (
SELECT id,price from TableA_Wk1
UNION ALL
SELECT id,price from TableA_Wk2
) t
GROUP BY t.id
Union the result set and then perform summation to get the summed value.
select sum(price) from (
select price from TableA_Wk1
union all
select price from TableA_Wk1
) as alais