Finding the largest price increase/decrease in a MySQL table - mysql

I am trying to find a way to get the largest price difference (in a time frame, e.g. 24 hours) in a MySQL table using a source and productId as reference.
Here is a sample product, productId 22.
id price createdAt updatedAt sourceId productId
21 799.00 2017-07-26 19:46:46 2017-07-26 19:46:45 1 22
853 920.00 2017-07-26 06:46:46 2017-07-26 06:46:46 1 22
855 799.00 2017-07-22 16:17:11 2017-07-22 16:17:11 2 22
851 770.00 2017-07-21 16:17:11 2017-07-21 16:17:11 1 22
856 799.00 2017-07-20 16:17:11 2017-07-20 16:17:11 2 22
852 599.00 2017-07-19 16:17:11 2017-07-19 16:17:11 1 22
857 810.00 2017-07-18 16:17:11 2017-07-18 16:17:11 2 22
858 799.00 2017-07-17 16:17:11 2017-07-17 16:17:11 2 22
In the example above for productId 22 I am sorting by createdAt, so in this scenario I'd take id 21 and substract it from id 853, this would give -121, meaning the product went down 121 dollars.
In the full data it's a mush up of prices, sourceIds and productIds. The goal here is to make a result look like this:
id createdAt sourceId productId adjustment
21 2017-07-26 19:46:46 1 22 -121
22 2017-07-26 16:46:46 2 22 201
23 2017-07-26 15:46:46 6 24 -20
Above is kind of how I am trying to get the data to look, so I'll know of the price difference of each product of each source. Then I can control the data, such as ordering by adjustment and seeing which source + product had the largest decrease or increase in a time frame.
I've tried doing a ton of sub-queries, I've probably put in a hundred examples that I've modified from Google. I can piece together parts of this, such as only getting products that have recieved a change of any kind from the past 24 hours. I've tried to merge the last two rows of each product Id, then do a math, and list all the products. It's been 2 days of trying to build this query, is it just best for me to not use queries for everything and do it on my backend?
I've even went to a support site like hackhands and they couldn't figure it out. I've exhausted all of my ideas.

This query breaks down the problem:
1) Getting the records corresponding to start_at time of the window for each product in order to get the baseline price.
2) Gets the the records for the max price for each product in the time frame.
3) Gets the records for the min price for each product in the time frame.
4) Combines 1 and 2 and 3 to form a single record per product and shows the info and the difference between base line price and the highest and lowest in the time frame.
If you only need the bigger of the two you can add and extra layer of select wrapping this query and user GREATER(a,b) to keep one diff or the other.
select BOWPRICE.product_id, BOWPRICE.created_at, BOWPRICE.price,
MAXPRICE.max_price_upd_time, MAXPRICE.max_price, ABS((BOWPRICE.price - MAXPRICE.max_price)) max_price_diff,
MINPRICE.min_price_upd_time, MINPRICE.min_price, ABS((BOWPRICE.price - MINPRICE.min_price)) min_price_diff
from
(
select mainA.product_id, mainA.created_at, mainA.price from SOTEST mainA
where id in (
select id
from SOTEST N
where created_at = (
select min(N1.created_at)
from SOTEST N1
where N1.created_at >= '2017-07-26 00:00:00'
and N1.product_id = N.product_id
)
group by mainT.product_id
)
) BOWPRICE,
(
select mainB.product_id, mainB.updated_at max_price_upd_time, mainB.price max_price from SOTEST mainB
where id in(
select id from SOTEST M
where M.price = (
select max(M1.price)
from SOTEST M1
where M1.created_at >= '2017-07-26 00:00:00'
and M1.created_at < '2017-07-27 00:00:00'
and M1.product_id = M.product_id
group by product_id LIMIT 1
)
)
) MAXPRICE,
(
select mainC.product_id, mainC.updated_at min_price_upd_time, mainC.price min_price from SOTEST mainC
where id in(
select id from SOTEST Q
where Q.price = (
select min(Q1.price)
from SOTEST Q1
where Q1.created_at >= '2017-07-26 00:00:00'
and Q1.created_at < '2017-07-27 00:00:00'
and Q1.product_id = Q.product_id
group by product_id LIMIT 1
)
)
) MINPRICE
where BOWPRICE.product_id = MAXPRICE.product_id
and BOWPRICE.product_id = MINPRICE.product_id

Related

How to subtract one column from another column finding the previous occurrence of the same id?

I am working with the Sakila video rental database that comes preloaded with MySQL.
I am trying to find the average number of days each video sits on the shelf before it is rented again.
In the rentals table you have the rental_id for each rental transaction, the inventory_id corresponding to the item that was rented, as well as the rental_date and return_date.
For each rental transaction I would like to look at the rental_date and find the difference from the return_date of the previous occurrence of the same inventory_id.
I know LAG() and LEAD() might be useful here, but I have no idea how to make it only consider other rows with the same inventory_id.
Sample data:
rental_id inventory_id rental_date return_date
-------------------------------------------------------
1 115 01-01-2005 01-05-2005
2 209 01-01-2005 01-04-2005
3 115 01-06-2005 01-10-2005
4 209 01-09-2005 01-14-2005
5 209 01-15-2005 01-20-2005
6 115 01-16-2005 01-20-2005
Desired output:
rental_id inventory_id rental_date return_date days_on_shelf
------------------------------------------------------------------------
1 115 01-01-2005 01-05-2005 NULL
2 209 01-01-2005 01-04-2005 NULL
3 115 01-06-2005 01-10-2005 1
4 209 01-09-2005 01-14-2005 5
5 209 01-15-2005 01-20-2005 1
6 115 01-16-2005 01-20-2005 6
Thank you to June7. The correct code should look like this:
SELECT
rental.rental_id,
rental.inventory_id,
inventory.film_id,
rental.rental_date,
rental.return_date,
IF(#lastid = rental.inventory_id,
DATEDIFF(rental.rental_date, #lastreturn),
NULL) AS days_on_shelf,
#lastid:=rental.inventory_id,
#lastreturn:=rental.return_date
FROM
rental
JOIN
inventory ON rental.inventory_id = inventory.inventory_id
ORDER BY rental.inventory_id , rental.rental_date
You seem to just want lag():
select t.*,
datediff(rental_date,
lag(return_date) over (partition by inventory_id order by rental_date)
) as days_on_shelf
from t

Is there a way to have a conditional statement for comparing of tables using MySQL only?

I am having a dilemma from comparing my tables.
My problem is, I want to get each sum, which depends on the pricing. Here is the table.
Main table
main_id main_price main_date_created
25 8.5 2019-08-16
26 11.5 2019-08-01
Total table
id main_id total_price date_generated
1 25 10 2019-08-16
2 25 10 2019-08-17
3 25 10 2019-08-18
4 25 10 2019-08-19
5 25 10 2019-08-20
6 25 10 2019-08-21
7 26 20 2019-08-01
8 26 5 2019-08-02
9 26 5 2019-08-03
10 26 10 2019-08-04
Price History table
id main_id changed_main_price price_date_changed
1 25 15 2019-08-18
2 26 20 2019-08-03
I don't know if there is a way to do this just by using MySQL, what I am trying to achieve is, the Total table will be sum by MONTH and YEAR and will be multiplied by their designated price that depends on the date whether if the price has changed or not . the SUM will from each month will be generated by multiplying with the main price in the Main table but if the price had changed from its original price which it is on the Price history table
The output should be like this if the conditional is possible:
id main_id total_price price_generated (which is the prices) date
1 25 170 (10+10*8.5) 8.5
2 25 610 (10+10+10+10*15) 15
3 26 287.5 (20+5*11.5) 11.5
4 26 300 (5+10*20) 20
Here is my existing query,
SELECT m.main_id
, m.main_price
, SUM(t.total_price) total_generated
, t.date_generated
FROM main m
INNER JOIN total t
ON m.main_id = t.main_id
GROUP
BY MONTH(t.date_generated);
I know that my query is not enough, and I still don't know if my idea is really possible :(.
I racked my brain. hahaha Is this you're after?
SELECT pricelist.id, pricelist.price, SUM(t.total_price), SUM(t.total_price) * pricelist.price,
year( pricelist.latestdate), month(pricelist.latestdate),
year( t.total_date_generated), month(t.total_date_generated)
from totaltable as t
LEFT JOIN (
(
select main_id as id, main_price as price, main_date_created as latestdate
from maintable
)
UNION ALL
(
select total_main_id, changed_main_price , price_date_changed
from pricehistorytable
)
) as pricelist on pricelist.id = t.total_main_id
GROUP BY pricelist.id , t.total_price, pricelist.price,
year( pricelist.latestdate), month(pricelist.latestdate),
year( t.total_date_generated), month(t.total_date_generated) ;

mysql group by day and count then filter only the highest value for each day

I'm stuck on this query. I need to do a group by date, card_id and only show the highest hits. I have this data:
date card_name card_id hits
29/02/2016 Paul Stanley 1345 12
29/02/2016 Phil Anselmo 1347 16
25/02/2016 Dave Mustaine 1349 10
25/02/2016 Ozzy 1351 17
23/02/2016 Jhonny Cash 1353 13
23/02/2016 Elvis 1355 15
20/02/2016 James Hethfield 1357 9
20/02/2016 Max Cavalera 1359 12
My query at the moment
SELECT DATE(card.create_date) `day`, `name`,card_model_id, count(1) hits
FROM card
Join card_model ON card.card_model_id = card_model.id
WHERE DATE(card.create_date) >= DATE(DATE_SUB(NOW(), INTERVAL 1 MONTH)) AND card_model.preview = 0
GROUP BY `day`, card_model_id
;
I want to group by date, card_id and filter the higher hits result showing only one row per date. As if I run a max(hits) with group by but I won't work
Like:
date card_name card_id hits
29/02/2016 Phil Anselmo 1347 16
25/02/2016 Ozzy 1351 17
23/02/2016 Elvis 1355 15
20/02/2016 Max Cavalera 1359 12
Any light on that will be appreciated. Thanks for reading.
Here is one way to do this. Based on your sample data (not the query):
select s.*
from sample s
where s.hits = (select max(s2.hits)
from sample s2
where date(s2.date) = date(s.date)
);
Your attempted query seems to have no relationship to the sample data, so it is unclear how to incorporate those tables (the attempted query has different columns and two tables).

Mysql best students in every class in a school

In MySql I need to select top student in every class in a school in termid=10 to get discount for next term enrollment .
Please notice that total is not in table(I put in below for clearing problem)
I have this workbook table for all students workbook:
id studentid classid exam1 exam2 total termid
1 2 11 20 40 60 10
2 1 22 40 20 60 10
3 4 11 40 20 60 10
4 5 33 10 60 70 10
5 7 22 10 40 50 10
6 8 11 10 30 40 10
7 9 33 20 45 65 10
8 11 11 null null null 10
9 12 54 null null null 02
10 13 58 null null null 02
1st challenge is : exam1 and exam2 are VARCHAR and total is not in table (as i explained).
2nd challenge is : as you can see in id=8 std #11 has not numbers
3rd challenge is : may be two students have top level so they must be in result.
I need result as :
id studentid classid exam1 exam2 total termid
1 2 11 20 40 60 10
3 4 11 40 20 60 10
4 5 33 10 60 70 10
2 1 22 40 20 60 10
i have this query but not work good as i mention.
SELECT DISTINCT id,studentid,classid,exam1,exam2,total,termid ,(CAST(exam1 AS DECIMAL(9,2))+CAST(exam2 AS DECIMAL(9,2))) FROM workbook WHERE ClassId = '10';
You can get the total for the students by just adding the values (MySQL will convert the values to numbers). The following gets the max total for each class:
select w.classid, max(coalesce(w.exam1, 0) + coalesce(w.exam2, 0)) as maxtotal
from workbook w
group by w.classid;
You can then join this back to the original data to get information about the best students:
select w.*, coalesce(w.exam1, 0) + coalesce(w.exam2, 0) as total
from workbook w join
(select w.classid, max(coalesce(w.exam1, 0) + coalesce(w.exam2, 0)) as maxtotal
from workbook w
group by w.classid
) ww
on w.classid = ww.classid and (coalesce(w.exam1, 0) + coalesce(w.exam2, 0)) = ww.maxtotal;
Another approach is to join the table with itself. You find out the max for each class and then join all students of this class which match the class max:
max for each class (included in the final statement already):
SELECT classid, MAX(CAST(exam1 AS UNSIGNED) + CAST(exam2 AS UNSIGNED)) as 'maxtotal'
FROM students
WHERE NOT ISNULL(exam1)
AND NOT ISNULL(exam2)
GROUP BY classid
The complete statement:
SELECT s2.*, s1.maxtotal
FROM (SELECT classid, MAX(CAST(exam1 AS UNSIGNED) + CAST(exam2 AS UNSIGNED)) as 'maxtotal'
FROM students
WHERE NOT ISNULL(exam1)
AND NOT ISNULL(exam2)
GROUP BY classid) s1
JOIN students s2 ON s1.classid = s2.classid
WHERE s1.maxtotal = (CAST(s2.exam1 AS UNSIGNED) + CAST(s2.exam2 AS UNSIGNED));
SQL Fiddle: http://sqlfiddle.com/#!2/9f117/1
Use a simple Group by Statement:
SELECT
studentid,
classid,
max(coalesce(exam1,0)) as max_exam_1,
max(coalesce(exam2,0)) as max_exam_2,
sum(coalesce(exam1,0) + coalesce(exam2,0)) as sum_exam_total,
termid
FROM
workbook
WHERE
termid=10
GROUP BY
1,2
ORDER BY
5
Try something like this:
SELECT id,studentid,classid,exam1,exam2,(CAST(exam1 AS DECIMAL(9,2))+CAST(exam2 AS DECIMAL(9,2))) AS total,termid FROM `workbook` WHERE ((CAST(exam1 AS DECIMAL(9,2))+CAST(exam2 AS DECIMAL(9,2)))) > 50
Thanks all my friends
I think combine between 2 answer in above is best :
SELECT s2.*, s1.maxtotal
FROM (SELECT ClassId, MAX(
coalesce(exam1,0)+
coalesce(exam2,0)
) as 'maxtotal'
FROM workbook
WHERE
(
termid = '11'
)
GROUP BY ClassId) s1
JOIN workbook s2 ON s1.ClassId = s2.ClassId
WHERE s1.maxtotal = (
coalesce(exam1,0)+
coalesce(exam2,0)
) AND (s1.maxtotal >'75');
last line is good for s1.maxtotal=0 (some times student scores have not be entered and all equals 0 so all will shown as best students) or some times we need minimum score (to enroll in next term).
So thanks all

Select more columns with GROUP_CONCAT( ) according to lowest date

I have one table accounts. I have written following query
chk_account= mysql_query("SELECT GROUP_CONCAT( DISTINCT user_id ) AS userlist
FROM `accounts`
");
From this I get users id only. With this query I also want to fetch data price and date with column name price and created but I need only to select with lowest date
I have table structure like this:
id user_id price created
1 31 10 2013-04-09 17:30:15
2 32 20 2013-04-10 20:24:40
3 31 30 2013-04-11 04:44:25
4 33 40 2013-04-12 05:47:18
5 34 50 2013-04-13 19:54:15
6 34 50 2013-04-14 14:27:15
7 35 10 2013-04-15 13:54:45
8 35 60 2013-04-16 12:24:35
9 35 10 2013-04-17 20:34:10
I suspect that you want the earliest date and price for each user. You can do this using group_concat(), using a query such as:
select USER_ID,
substring_index(group_concat(price order by created), ',', 1) as price,
min(created)
from accounts a
group by user_id