Here is my SQl table:
Item_id city_product_id auto_inc price
1. XYZ CHDELCLAPTOPDELLINSPIRON 1 1500
2. ABCD CHDELCLAPTOPDELLVOSTR816 2 1200
3. ABCD CHDELCLAPTOPDELLVOSTR816 3 1000
Here is my SQL query:
SELECT city_product_id, item_id, auto_inc, MIN( price ) AS minPrice
FROM sellers_product GROUP BY city_product_id
This query is returning this output:
city_product_id item_id auto_inc price
CHDELCLAPTOPDELLINSPIRON XYZ 1 1500
CHDELCLAPTOPDELLVOSTR816 ABCD 2 1000
The only problem is why it is returning auto_inc as 2 when it should return 3 because 1000 is less than 1200.
Non aggregated fields in presence of group by will give indeterminate results you can use a self join to determine the correct row with minimum price
SELECT p.*
FROM sellers_product p
join (select city_product_id,MIN( price ) AS minPrice
from sellers_product
GROUP BY city_product_id) p1
on(p.city_product_id = p1.city_product_id and p.price = p1.minPrice )
Demo
MySQL's group-by function uses the first-encountered row to fill in a value for any non-grouped field in a result row.
SELECT city_product_id, item_id, auto_inc, price
from ( SELECT *
FROM sellers_product
ORDER BY price ASC) AS h
GROUP BY city_product_id;
http://sqlfiddle.com/#!2/2d5b2/1
Related
I need to write a query to get the sum of values for each category for a list of given dates. If a value doesn't exist for a category, we should get the value from the previous date. Basically something like "max per category per date". The end goal is a trend chart. If a previous value for a category doesn't exist, setting the value to 0 is fine.
See tables and result below:
Category
id
name
1
savings
2
cash
3
stocks
Item
id
categoryId
value
createdAt
1
1
100
2022-01-01
2
2
20
2022-01-01
3
3
500
2022-01-01
4
2
0
2022-01-02
5
3
1000
2022-01-03
Result
createdAt
total
2022-01-01
620
2022-02-02
600
2022-02-03
1100
To get a result for a single date I could do something like this:
SELECT SUM(value) as total
FROM Category
LEFT JOIN (
SELECT id, categoryId, value
FROM Item
WHERE id IN (
SELECT MAX(id) FROM Item WHERE createdAt <= '2022-01-10' GROUP BY categoryId)
) items ON Category.id = items.categoryId;
I have absolutely no clue on how to approach doing this for multiple dates, eg. if my input would be every day in the month of January 2022. I'm running on MySQL 8.0.23. Also, if this is not feasible with a single query, I'm up for ideas. Do you have any suggestions?
Try this:
with u as
(select id as categoryId from Category),
v as
(select distinct createdAt from Item),
w as
(select * from u cross join v),
x as
(select createdAt,
categoryId,
(select value
from Item
where categoryId = w.categoryId and createdAt <= w.createdAt
order by createdAt desc
limit 1) as value
from w)
select createdAt, sum(value) as total
from x
group by createdAt
Basically getting all the combinations of the creation dates with the categoryIds, then using a subquery to get the value of the closest or equal date for each categoryId.
A Fiddle.
One option uses window functions such as SUM() OVER () and LAG() such as
WITH i AS
(
SELECT SUM(`value`) OVER (PARTITION BY `createdAt`,`categoryId` ORDER BY `createdAt`) AS total_sofar,
LAG(`value`,1,0) OVER (PARTITION BY `categoryId` ORDER BY `createdAt`) AS lg,
`createdAt`
FROM Item
)
SELECT DISTINCT `createdAt`,
SUM(total_sofar) OVER (ORDER BY `createdAt`)-SUM(lg) OVER (ORDER BY `createdAt`) AS total
FROM i
ORDER BY `createdAt`
as you have MySQL DBMS of version 8.0. The trick is grouping(partitioning by categoryId along with the LAG at the first query)
Demo
This question already has answers here:
MySQL select before after row
(4 answers)
Closed 3 years ago.
I have a table with a value column. I need to select the line chosen by the user (on the front), one line above and one line below, so:
My 'orders' table rows
----------------------------------------------
id | price |
----------------------------------------------
1 | 1500.00 |
2 | 1380.00 |
3 | 1880.00 |
4 | 1900.00 |
5 | 1450.00 |
6 | 1700.00 |
If the person chose: 1450.00, I want to bring 1450.00, 1380.00 and 1500.00. Is it possible to make this MySql select? or will i have to do this in php?
I only have the initial query for now:
SELECT * FROM `orders`
ORDER BY price;
You could select max and min price to get row. Let try this code:
SELECT *
FROM orders A
WHERE A.price = 1450.00
OR A.price = (SELECT MAX(B.price) FROM orders B WHERE B.price < 1450.00)
OR A.price = (SELECT MIN(B.price) FROM orders B WHERE B.price > 1450.00)
One way you could do it is using 2 MySQL statements. Something like:
SELECT * FROM `orders` WHERE `price`>=$user_price ORDER BY `price` ASC LIMIT 2
Which should give you the user's selected price and the row above. Then you can execute
SELECT * FROM `orders` WHERE `price`<$user_price ORDER BY `price` DESC LIMIT 1
Which should give you the row below.
I'm not sure if there's a way to combine the two queries, but if I do find anything I'll update the answer :)
Here's how to get this, use max() on < 1450 and and min() on > 1450
select * from test
where price in
(select price from test where price = 1450)
or price in
(select max(price) from test where price < 1450)
or price in
(select min(price) from test where price > 1450)
instead of using or, use in instead to more cleaner.
select * from test
where price in (1450,
(select max(price) from test where price < 1450),
(select min(price) from test where price > 1450))
see dbfiddle
If the prices are unique and you want exactly three rows:
(select o.*
from orders o
where o.price <= :price
order by o.price
limit 2
) union all
(select o.*
from orders o
where o.price > :price
order by o.price desc
limit 1
);
Your question does not clarify what to do in these cases:
When the price is less than or equal to the minimum price.
When the price is greater than or equal to the maximum price.
When there are duplicate prices.
I think this query should work
select price
from orders
where price <= (select min(price) from orders where price > 1450.00)
order by price desc
limit 3
Im trying to get the mode (the value that appears most often in a set of data) of price for each store in the following table
create table t_products (
store_id int,
product varchar(20),
price int
)
I already have this query which retrieves all the ocurrences of each price in each store
SELECT store_id, price, count(price)
FROM t_products
GROUP BY store_id, price
ORDER BY count(price) DESC;
What else is missing? I was trying to use max() function to get the highest price for each store in several ways with no success.
Thanks in advance
PD this is the result of my current query.
store_id|price|count(price)
2 40 5
1 70 5
2 90 4
3 60 2
1 60 1
3 50 1
3 80 1
1 50 1
I only want to keep
store price
2 40
1 70
3 60
select tmp.store_id, tmp.price from (
SELECT store_id, price
FROM t_products
GROUP BY store_id, price
ORDER BY count(price) DESC
) as tmp
group by tmp.store_id
Good luck )
SELECT store_id, value
FROM (SELECT store_id, value, count(value) c
FROM t_products
GROUP BY store_id, value
ORDER BY count(value) DESC) ds
GROUP BY store_id
HAVING max(ds.c);
I have a table with prices and dates on product:
id
product
price
date
I create a new record when price change. And I have a table like this:
id product price date
1 1 10 2014-01-01
2 1 20 2014-02-17
3 1 5 2014-03-28
4 2 25 2014-01-05
5 2 12 2014-02-08
6 2 30 2014-03-12
I want to get last price for all products. But when I group with "product", I can't get a price from a row with maximum date.
I can use MAX(), MIN() or COUNT() function in request, but I need a result based on other value.
I want something like this in final:
product price date
1 5 2014-03-28
2 30 2014-03-12
But I don't know how. May be like this:
SELECT product, {price with max date}, {max date}
FROM table
GROUP BY product
Alternatively, you can have subquery to get the latest get for every product and join the result on the table itself to get the other columns.
SELECT a.*
FROM tableName a
INNER JOIN
(
SELECT product, MAX(date) mxdate
FROM tableName
GROUP BY product
) b ON a.product = b.product
AND a.date = b.mxdate
I think the easiest way is a substring_index()/group_concat() trick:
SELECT product,
substring_index(group_concat(price order by date desc), ',', 1) as PriceOnMaxDate
max(date)
FROM table
GROUP BY product;
Another way, that might be more efficient than a group by is:
select p.*
from table t
where not exists (select 1
from table t2
where t2.product = t.product and
t2.date > t.date
);
This says: "Get me all rows from the table where the same product does not have a larger date." That is a fancy way of saying "get me the row with the maximum date for each product."
Note that there is a subtle difference: the second form will return all rows that on the maximum date, if there are duplicates.
Also, for performance an index on table(product, date) is recommended.
You can use a subquery that groups by product and return the maximum date for every product, and join this subquery back to the products table:
SELECT
p.product,
p.price,
p.date
FROM
products p INNER JOIN (
SELECT
product,
MAX(date) AS max_date
FROM
products
GROUP BY
product) m
ON p.product = m.product AND p.date = m.max_date
SELECT
product,
price,
date
FROM
(SELECT
product,
price,
date
FROM table_name ORDER BY date DESC) AS t1
GROUP BY product;
The statement below is to get all non-duplicate IDs from the products table. Is there a way I can get the total count of rows that are outputted by this sql statement?
select min(product_id) from products
where market_code = 'germany'
group by product_code
sample table data:
product_id market_code product_code
1 uk AAA
1 uk AAA
1 uk AAA
2 germany BAA
2 germany BAA
3 uk BAA
Thanks
You can simply do this:
SELECT COUNT(*)
FROM
(
select min(product_id) from products
where market_code = 'germany'
group by product_code
) AS t;
Actually your query is not what you said "The statement below is to get all unique/non-duplicate IDs from the products table." , It will select lowest product_id for product_code , not unique , for example if there are product_id - 2 and product_id - 3 for product_code A , it will only return product_id - 2 , it is a minimum value not unique , if you want unique you could do this way
SELECT product_code,product_id,count(*)
FROM TABLE
GROUP BY product_code,product_id
if you want just unique/non-duplicate ID-s and their count you can select with this query
SELECT product_id,count(*)
FROM table
GROUP BY product_id
The statement:
select min(product_id)
from products
where market_code = 'germany'
group by product_code;
is going to have as many rows as there are product code values in Germany. If you assume that a given product id never has two codes (which is true of your sample data), then the following counts the products in Germany without using product id at all:
select count(distinct product_code)
from products
where market_code = 'germany';