This question is an extension to this earlier question (not asked by me).
I have a table consisting of these fields:
id | date_from | date_to | price | priceName
--------------------------------------------------------
CK1 22-12-2012 29-12-2012 800 low
CK1 22-12-2012 29-12-2012 1200 medium
CK2 22-12-2012 29-12-2012 1400 high
CK2 22-12-2012 29-12-2012 1800 very high
CK2 22-12-2012 29-12-2012 2200 extortionate
How do I create a SQL select that groups the results by ID, DATE_FROM, DATE_TO and picks the lowest value from price and the priceName that is associated with the lowest price?
So the result would be
CK1 22-12-2012 29-12-2012 800 low
CK2 22-12-2012 29-12-2012 1400 high
From the previous question I can do:
select id, date_from, date_to, min(price)
from table
group by id, date_from, date_to
How do I extend this to only select the priceName that matches the min(price)? Grouping by priceName won't work because it does not constrain to the min(price).
You can use subquery.
Select Table.id,Date_from,date_to,MinPrice,PriceName
from
(select id, min(price) as MinPrice
from table
group by id) t1
INNER JOIN table ON t1.id=table.id and t1.MinPrice=table.Price
Group by id,Date_from,date_to,MinPrice,PriceName
Try this:
Select t.*,t1.priceName from (
select id, date_from, date_to, min(price)
from table
group by id, date_from, date_to) t
join table t1 on t.id =t1.id
and t.date_from =t1.date_from
and t.date_to =t1.date_to
and t.price =t1.price
One way would be to use the rank window function:
SELECT id, date_from, date_to, price, priceName
FROM (SELECT id, date_from, date_to, price, priceName,
RANK() OVER (PARTITION BY id, date_from, date_to
ORDER BY price ASC) AS rk
FROM mytable) t
WHERE rk = 1
Using CTE:
WITH cte (id, date_from, date_to, minprice) AS (
SELECT id, date_from, date_to, [minprice] = min(price)
FROM table_name
GROUP BY id, date_from, date_to)
SELECT
c.id, c.date_from, c.date_to, c.[minprice], t.priceName
FROM table_name t
JOIN cte c
ON t.id = c.id
AND t.date_from = c.date_to
AND t.data_to = c.date_to
Related
There is a table like this, how can I get customer_id, amount_spent, top_item out of it?
amount_spent the amount spent on all items by this customer
top_item, which displays the name of the item for which the customer has spent the most money
I have tried the following query, however I cannot output the top_1 item with it
select customer_id, sum(item_number * item_price) as amount_spent_1m
from temp
group by customer_id
Check the demo here.
You can achieve it as below :
select customer_id, sum(item_number * item_price) as amount_spent_1m,
item_name as top_item_1m
from temp
group by customer_id, item_name
order by amount_spent_1m desc;
It gives me the following result :
I am sure there is a way to do this with one less step but my brain is not seeing it right now -
SELECT customer_id, amount_spent, item_name AS top_item
FROM (
SELECT *,
ROW_NUMBER() OVER (PARTITION BY customer_id ORDER BY item_total DESC) rn,
SUM(item_total) OVER (PARTITION BY customer_id) amount_spent
FROM (
SELECT customer_id, item_id, item_name, SUM(item_price * item_number) item_total
FROM table1
GROUP BY customer_id, item_id, item_name
) t1
) t2
WHERE rn = 1
db<>fiddle
I need to get my data set as this table
I am trying to get eligible set like this, need to group_concat pinged set also
x.id IN (SELECT MAX(x.id) FROM x WHERE ping rider id IS NULL GROUP BY orderId)
You can assign a group based on the cumulative number of non-null values in eligible_riders. Then aggregate and take the last value:
select og.*
from (select order_id, grp, max(eligible_riders) as eligible_riders,
group_concat(rider_id) as riders,
row_number() over (partition by order_id order by min(id) desc) as seqnum
from (select t.*,
sum(eligible_riders <> '') over (partition by order_id order by id) as grp
from t
) t
group by order_id, grp
) og
where seqnum = 1;
Hmmm . . . You could also do this with a correlated subquery, which might look a bit simpler:
select order_id, max(eligible_riders) as eligible_riders,
group_concat(rider_id) as riders
from t
where t.id >= (select max(t2.id)
from t t2
where t2.order_id = t.order_id and
t2.eligible_riders <> ''
)
group by order_id;
For performance, you want an index on (order_id, eligible_riders).
I have a 80 tables and I want to filter who has the highest price among 80 tables. I plan on using this query:
SELECT id
FROM (SELECT id, price FROM T1 WHERE price = (SELECT MAX(price) FROM T1)
UNION
SELECT id, price FROM T2 WHERE price = (SELECT MAX(price) FROM T2)
UNION
SELECT id, price FROM T3 WHERE price = (SELECT MAX(price) FROM T3)
) AS M
ORDER BY price DESC
LIMIT 1
But I find it inefficient. Is there other way?
I think this would be a lot faster.
SELECT id, price FROM t1
UNION SELECT id, price FROM t2
UNION SELECT id, price FROM t3
ORDER BY price DESC
LIMIT 1
I have 3 tables and my query is :
SELECT BRAND, AMOUNT FROM
(
SELECT BRAND, AMOUNT FROM SALES1
UNION
SELECT BRAND, AMOUNT FROM SALES2
UNION
SELECT BRAND, AMOUNT FROM SALES3
)
SALES 1 TABLE HAS BRAND: A AND AMOUNT: 50
SALES 3 TABLE HAS BRAND: A AND AMOUNT: 100
I want to get the amount 50 and disregard 100. I want to ask if is there any priority when using union?
If you want the first occurrence, you should use union all rather than union. This is important for performance reasons, because union does unnecessary duplicate elimination.
Then use the not exists clauses for each subquery:
(SELECT BRAND, AMOUNT
FROM SALES1
) UNION ALL
(SELECT BRAND, AMOUNT
FROM SALES2 s2
WHERE NOT EXISTS (SELECT 1 FROM SALES1 s1 WHERE s1.BRAND = s2.BRAND)
) UNION ALL
(SELECT BRAND, AMOUNT
FROM SALES3 s3
WHERE NOT EXISTS (SELECT 1 FROM SALES1 s1 WHERE s1.BRAND = s3.BRAND) AND
NOT EXISTS (SELECT 1 FROM SALES2 s2 WHERE s2.BRAND = s3.BRAND)
)
SELECT BRAND, AMOUNT
FROM
( SELECT BRAND, AMOUNT, 1 AS priority
FROM SALES1
UNION ALL
SELECT BRAND, AMOUNT, 2 AS priority
FROM SALES2
UNION ALL
SELECT BRAND, AMOUNT, 3 AS priority
FROM SALES3
)
ORDER BY priority
LIMIT 1;
you need a "where not exists"(or "not in" or a "left join") within your unions:
(SELECT BRAND, AMOUNT FROM SALES1 )
UNION
(SELECT BRAND, AMOUNT FROM SALES2)
UNION
(SELECT BRAND, AMOUNT FROM SALES3 where brand not in (SELECT BRAND FROM SALES1))
I have a table Like below.
I want the product_id of Minimum, Maximum and Average cost products in a single query.
CREATE TABLE productlist(product_id INT NOT NULL PRIMARY KEY AUTO_INCREMENT,
cost INT);
INSERT INTO productlist(cost)
VALUES('2450'),
('2200'),
('2580'),
('2405'),
('3500'),
('1500'),
('1800'),
('1520'),
('1740'),
('1940'),
('2940'),
('1250'),
('1290'),
('1390'),
('2900');
Output:
Min 12
Max 5
Avg 2093
I tried like one below but its not working.
SELECT product_id, MIN(cost) as mincost
FROM productlist
GROUP BY product_id
ORDER BY mincost ASC
LIMIT 0,1
UNION
SELECT product_id, max(cost) as maxcost
FROM productlist
GROUP BY product_id
ORDER BY maxcost DESC
LIMIT 0,1
How should I do this
select 'Min', product_id
from productlist
where cost = (select min(cost) from productlist)
UNION
select 'Max', product_id
from productlist
where cost = (select MAX(cost) from productlist)
UNION
select 'Avg', round(AVG(cost),0) as Avg
from productlist
select product_id, cost
from productlist where cost = (SELECT max(cost)from productlist)
union
select product_id, cost
from productlist where cost = (SELECT min(cost)from productlist)
union
select product_id, cost
from productlist where cost = (SELECT x.cost from productlist x, productlist y
GROUP BY x.cost
HAVING SUM(SIGN(1-SIGN(y.cost-x.cost))) = (COUNT(*)+1)/2)
This uses median, returns product id in every case
the output you want is not coming by the query you wrote
you need to try out this one for getting the required output
select 'Min', product_id
from productlist
where cost = (select min(cost) from productlist)
UNION
select 'Max', product_id
from productlist
where cost = (select MAX(cost) from productlist)
UNION
select 'Avg', floor(AVG(cost)) as Avg
from productlist
This answers your question exactly but it should be noted that it costs 3 table scans to find this data. Also, the example in the question suggests that the average value is truncated down to 2093 from 2093.67. It is perhaps better to replace this with round.
SQL Fiddle
SELECT concat('Min ', product_id)
FROM productlist
WHERE cost = (SELECT min(cost) from productlist)
UNION ALL
SELECT concat('Max ', product_id)
FROM productlist
WHERE cost = (SELECT max(cost) from productlist)
UNION ALL
SELECT concat('Avg ', truncate(avg(cost), 0))
FROM productlist
This is to select all the products
SELECT
max(cost), MIN(cost), AVG(cost)
FROM
productlist
GROUP BY
product_id
GROUP BY is not exactly required here. But seems like you are beginner, googling to will help you.
For your question try this.
SELECT
(select CONCAT(product_id, '-', cost) from productlist group by product_id order by cost DESC limit 1) as MAX,
(select CONCAT(product_id, '-', cost) from productlist group by product_id order by cost ASC limit 1) as MIN,
(select avg(cost) from productlist) as AVG
FROM
productlist limit 1