mysql - How to calculate mode several times in a table - mysql

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);

Related

MYSQL Recursive query with conditions

I have 2 tables,
the first table contains id_product, its rate and its price.
ID_product
rate
Price
1
TSA1
0.12
2
TSA1
1.5
1
TSA2
0.14
2
TSA2
1.7
1
TSA3
NULL
2
TSA3
1.7
1
TASM4
1.68
I have an other table which contains a rate and its rate destination if the price for its rate is NULL. Its for always has a price for each product. Here for example, the product 1 doesnt have a price for the rate TSA3. The correspondance table says that if it doesnt have a price for this rate, use the price of TASM4.
Origin_rate
Destination_rate
TSA1
TAS2
TSA2
TAS3
TSA3
TASM4
So, How can I complete my first table? I think, i need a recursive query, but i dont know how to do it in SQL.
This query gets you the price hirarchically:
with recursive cte(id_product, rate, price, origin_rate) as
(
select id_product, rate, price, rate
from mytable
union all
select cte.id_product, cte.rate, t.price, t.rate
from cte
join map on map.origin_rate = cte.origin_rate
left join mytable t on t.id_product = cte.id_product
and t.rate = map.destination_rate
where cte.price is null
)
select id_product, rate, price
from cte
where price is not null
order by id_product, rate;

Get sum of values for multiple categories for a given list of dates

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

Customer partitioning in sql query

I have a table with following format -
Customer_id Purchase_date
c1 2015-01-11
c2 2015-02-12
c3 2015-11-12
c1 2016-01-01
c2 2016-12-29
c4 2016-11-28
c4 2015-03-15
... ...
The table essentially contains customer_id with their purchase_date. The customer_id is repetitive based on the purchase made on purchase_date. The above is just a sample data and the table contains about 100,000 records.
Is there a way to partition the customer based on pre-defined category data
Category Partitioning
- Category-1: Customer who has not made purchase in last 10 weeks, but made a purchase before that
- Category-2: Customer who as not made a purchase in last 5 weeks, but made purchase before that
- Category-3: Customer who has made one or more purchase in last 4 weeks or it has been 8 weeks since the first purchase
- Category-4: Customer who has made only one purchase in the last 1 week
- Category-5: Customer who has made only one purchase
What I'm looking for is a query that tells customer and their category -
Customer_id Category
C1 Category-1
... ...
The query can adhere to - oracle, postgres, sqlserver
From your question it seems that a customer can fall in multiple categories. So lets find out the customers in each category and then take UNION of the results.
SELECT DISTINCT Customer_Id, 'CATEGORY-1' AS Category FROM mytable GROUP BY
Customer_Id HAVING DATEDIFF(ww,MAX(Purchase_date),GETDATE()) > 10
UNION
SELECT DISTINCT Customer_Id, 'CATEGORY-2' AS Category FROM mytable GROUP BY
Customer_Id HAVING DATEDIFF(ww,MAX(Purchase_date),GETDATE()) > 5
UNION
SELECT DISTINCT Customer_Id, 'CATEGORY-3' AS Category FROM mytable GROUP BY
Customer_Id HAVING DATEDIFF(ww,MAX(Purchase_date),GETDATE()) < 4 OR
DATEDIFF(ww,MIN(Purchase_date),GETDATE()) =8
UNION
SELECT DISTINCT Customer_Id, 'CATEGORY-4' AS Category FROM mytable WHERE
DATEDIFF(ww,Purchase_date,GETDATE())<=1 GROUP BY Customer_Id having
COUNT(*) =1
UNION
SELECT DISTINCT Customer_Id, 'CATEGORY-5' AS Category FROM mytable GROUP BY
Customer_Id HAVING COUNT(*) =1
ORDER BY Category
Hope this serves your purpose.
Thanks
you can use something like this
with myTab as (
SELECT Customer_id ,MIN(Purchase_date) AS Min_Purchase_date,MAX(Purchase_date) AS Max_Purchase_date
, SUM(CASE WHEN Purchase_date>= DATEADD(WEEk ,-1,GETDATE()) THEN 1 ELSE 0 END ) AS Count_LastWeek
, COUNT(*) AS Count_All
FROM Purchases_Table
GROUP BY Customer_id
)
SELECT Customer_id
, CASE WHEN Max_Purchase_date < DATEADD(WEEK,-10,GETDATE()) THEN 'Category-1'
WHEN Max_Purchase_date < DATEADD(WEEK,-5,GETDATE()) THEN 'Category-2'
WHEN Max_Purchase_date >= DATEADD(WEEK,-4,GETDATE())
OR DATEDIFF(WEEK, Min_Purchase_date,Max_Purchase_date) >= 8 THEN 'Category-3'
WHEN Count_LastWeek = 1 THEN 'Category-4'
WHEN Count_All = 1 THEN 'Category-5'
ELSE 'No Category'
END
FROM myTab

which customer number(numbers) occur max time in a table

I have a table ORDERS which has something like this value ,
customerNumber | orderNumber(PK)
40 1
30 2
40 3
20 4
30 5
So, this table has customerNumbers 40 and 30 placing the max orders. Can anyone tell me a MySQL query to return the customerNumber (numbers), i dont want the count of the orders, just want the customer (cutomers) with the max order placed .
Thanks.
You can use below statement to get the Customer who placed maximum orders.
SELECT customerNumber FROM orders
GROUP BY customerNumber
ORDER BY COUNT(orderNumber) DESC LIMIT 1;
I should get deservedly flamed for this, but hey, the sun's out and it's feeling like a good day...
SELECT x.customernumber
FROM
( SELECT customernumber
, COUNT(*) total
FROM my_table
GROUP
BY customernumber
) x
JOIN
( SELECT COUNT(*) total
FROM my_table
GROUP
BY customernumber
ORDER
BY total DESC
LIMIT 1
) y
ON y.total = x.total;

Sql gruoup by clause not fetching desired result?

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