find price difference for different date - mysql

how find difference of price for two selected day. my table as shown
---------------------------------------
id price date product
---------------------------------------
1 10 15-12-2013 pen
2 40 15-12-2013 book
3 15 16-12-2013 pen
4 42 16-12-2013 book
-------------------------------------
i want an sql query to get output like, if startdate:15-12-2013 & enddate: 16-12-2013
product startdate(15-12-2013) enddate(16-12-2013) difference
--------------------------------------------------------------
pen 10 15 5
book 40 42 2
--------------------------------------------------------------

Maybe something like this?
select
p1.product,
p1.price,
p2.price,
p1.price - p2.price as diff
from
product p1,
product p2
where
p1.product=p2.product and
date(p1.date)='2013-12-15' and
date(p2.date)='2013-12-16'
If performance is a question then this link can provide a better alternative for the date matching part: MySQL SELECT WHERE datetime matches day (and not necessarily time)

Try this:
SELECT product, StartDatePrice, EndDatePrice, (EndDatePrice - StartDatePrice) AS Difference
FROM (SELECT product, MAX(IF(a.date = '15-12-2013', a.price, 0)) AS StartDatePrice,
MAX(IF(a.date = '16-12-2013', a.price, 0)) AS EndDatePrice
FROM tableA a
GROUP BY product
) AS A;

If you insert a row on your prices table whenewer a price changes, and not every day, you should consider using this query:
SELECT
p1.product,
p1.price as stardtade,
p2.price as enddate,
p2.price-p1.price as difference
FROM
prices p1 INNER JOIN (SELECT product, MAX(dt) max_dt
FROM prices
WHERE dt<='2013-12-15'
GROUP BY product) st
ON p1.product=st.product AND p1.dt = st.max_dt
INNER JOIN
prices p2
ON p1.product=p2.product
INNER JOIN (SELECT product, MAX(dt) max_dt
FROM prices
WHERE dt<='2013-12-16'
GROUP BY product) ed
ON p2.product=ed.product AND p2.dt = ed.max_dt
it is more complicated, but it will work even if some dates are not present in your table. In that case it will use the lask known value for the price.
Please see fiddle here.

Related

Difficult order / group by / count

I've got 3 simple tables, but my query is difficult
Sellers table :
seller_id | name
1 john
2 paul
5 fred
6 robert
etc ...
Transactions table (only 3 values for the moment) :
trans_id | name
1 BUY
2 SELL
3 EXCHANGE
Operations table :
seller_id | trans_id | datetime
2 1 ....
2 2 ....
6 1 ....
2 3 ....
6 1 ....
This tables records all the sellers' transactions and their moment.
I would like to obtain, in the last day, or in a time interval
seller name, number of buy-transaction order by number of buy-transaction in the interval
seller name, number of buy-or-sell-transaction order by number buy-or-sell-transaction in the interval
I've tried many things, strange things taht mysql does'nt like, but I can't succeed ... thanks !
Here is a solution for your first query, ie "seller name, number of buy-transaction order by number of buy-transaction in the interval" :
SELECT
S.name,
COUNT(1) AS total
FROM operations O
JOIN sellers S on O.seller_id = S.seller_id
JOIN transactions T on O.trans_id = T.trans_id
WHERE O.datetime >= CURDATE() AND T.name = 'BUY'
GROUP BY S.name
ORDER BY total
Obviously, the second query is nearly the same, the where clause just changes a little, see the following :
SELECT
S.name,
COUNT(1) AS total
FROM operations O
JOIN sellers S on O.seller_id = S.seller_id
JOIN transactions T on O.trans_id = T.trans_id
WHERE O.datetime >= CURDATE()-1 AND T.name IN ('BUY','SELL')
GROUP BY S.name
ORDER BY total
To be honest you could even remove the join with transactions table and use O.trans_id in your where clause.
SEE DEMO HERE
Here solution for your first query
Select a.name, a.count from
(select seller.name name, Count(Transaction.Tran_id) count
from seller, Transaction, Operation
where seller.Seller_id = Operation.Seller_Id
and Transaction.Tran_id = Operation.Tran_id
and Transaction.Tran_id=1
and Operation.datetime between (datetime 1 & datetime2)
group by seller.name) a
order by a.count
Second solution is :-
Select a.name, a.count from
(select seller.name name, Count(Transaction.Tran_id) count
from seller, Transaction, Operation
where seller.Seller_id = Operation.Seller_Id
and Transaction.Tran_id = Operation.Tran_id
and Transaction.Tran_id in (1, 2)
and Operation.datetime between (datetime 1 & datetime2)
group by seller.name) a
order by a.count

Getting data between certain dates for the entries which are not present before the time period mentioned

I have this date set table:
Product Entry_Date
1-A 18-02-2020
2-A 19-02-2020
1-A 23-02-2020
3-C 25-02-2020
4-D 26-02-2020
2-A 27-02-2020
I need those products which have Entry_Date between 23rd to 27th Feb BUT do not have entries before.
For eg. the output should be
Product
3-C
4-D
I tried two approaches:
This works:
select Product
from table a join (select Product, min(Entry_date) as min_date from table) b on a.Product = b.Product
where Entry_date between '23-02-2020' and '27-02-2020'
and b.min_date >='23-02-2020'
and this does not:
select Product
from table
where Entry_Date between '23-02-2020' and '27-02-2020'
group by 1
having min(Entry_Date)>='23-02-2020'
Is there any elegant way of doing this. Why does the second method does not work?
Use aggregation and min() in the having clause:
select product
from t
group by product
having min(Entry_Date) between '2020-02-23' and '2020-02-27';
Here is a db<>fiddle.
Note that I also fixed your date constants so they are YYYY-MM-DD standard.

How to query historical prices where there are no initial dates nor end dates?

I'm trying to make a SQL query to find the product that has raised the least amount of money, but I'm facing a problem, and it is that I have a table which keeps track of different dates for prices, for example Product 1 has a price of 5000 for all the recipts purchased between 2011-01-01 and the next date of a price change and that is 2012-01-01, on the other hand Product 1 has the latest price date as 2015-01-01 and its price is 5600, so it means that any recipt purchased from 2015-01-01 to an actual date has a price of 5600.
Here is a SQL Fiddle of the current problem:
http://sqlfiddle.com/#!9/62ec25/9
And the query I did to get an aproximation to the answer:
select pr.productName, sum(d.quantity*p.price)
from details d, product pr, price p, recipts r
where d.Product_ref=pr.ref
and pr.ref=p.Product_ref
and r.numRecipt=d.Recipts_numRecipt
group by pr.productName
order by 2 asc;
I'm pretty sure the query is wrong because I'm not taking into consideration the historical price for each product, but I cannot find a way to make use of the "in between" SQL operator, How can I get the expected result?
I think you'd want to get your price table into a structure that looks like:
| product_ref | price | startDate | endDate |
Then build a query that joins on that table where the purchase date is between the price date range:
SELECT
pr.productName,
SUM(d.quantity * p.price)
FROM
details d
INNER JOIN product pr ON d.product_ref = pr.ref
INNER JOIN
(
SELECT
p.product_ref,
p.price,
MIN(p.priceDate) AS StartDate,
MIN(p1.priceDate) AS EndDate
FROM price p
LEFT JOIN price p1 ON p.product_ref = p1.product_ref
WHERE
p.priceDate < p1.priceDate
GROUP BY p.product_ref, p.price
) p ON pr.ref = p.product_ref
INNER JOIN recipts r ON r.numRecipt = d.recipts_numRecipt
WHERE
r.dateOfPurchase >= p.startDate AND r.dateOfPurchase < p.endDate
GROUP BY pr.productName

How do optimise sql query using join between multiple tables

i have two tables having following structure
Table A
itemId categoryId orderDate
==========================================
1 23 2016-11-08
1 23 2016-11-12
1 23 2016-11-16
Table B have the structure
categoryId stock price
==========================================
23 500 600
However mine desired output should be as like
Result C
price stock orderdate qty
600 500 2016-11-08 (first order date) 3 (3 time appearance in first table)
Here is what i have tried so far
select b.price,b.stock from B b, A a
where b.categoryId = (
select a.categoryId
from A
GROUP BY categoryId
HAVING COUNT(categoryId)>1
)
and (a.orderdate = (
select MIN(orderdate)
from A
where categoryId = b.categoryId)
)
i have following result
price stock orderdate
600 500 2016-11-08
i have no idea how do find qty as it is appeared 3 times in first table.
I think you want the records in table a grouped by item id and category id, so include these two in your group by statement. Then the other columns you have to aggregate using MIN, MAX, AVG, SUM, etc. I use MIN which will give you the smallest number in the group for that particular column, although it shouldn't matter in this case whether you use MIN or MAX or AVG - it's all the same. Then COUNT(*) will just count the number of recrods in the group.
Also, joins are generally preferred over listing tables with commas.
SELECT a.itemid, a.categoryid, MIN(b.price), MIN(b.stock), min(a.orderdate), count(*) as qty
FROM a
INNER JOIN b ON a.categoryid = b.categoryid
GROUP BY a.itemid, a.categoryid
You also need to select COUNT(*)
how about use following sql
select min(price), min(stock), min(orderDate), COUNT(categoryId)
from A,B where A.categoryId = B.categoryId
GROUP by A.categoryId
You could create views for your subqueries and give them meaningful names e.g. CategoriesUsedInMultipleOrders, MostRecentOrderByCategory. This would 'optimize' you query by abstracting away complexity and making it easier for the human reader to understand.
This is the Query with the appropriate join method see Result:
SELECT B.price, B.stock, MIN( A.orderDate ) AS orderdate, COUNT( * ) AS qty
FROM TableA A, TableB B
WHERE A.categoryId = B.CategoryId
GROUP BY A.categoryId, B.price, B.stock

How to get rows with max date when grouping in MySQL?

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;