Reputation: 568
Based on SQL subtract two rows based on date and another column I had a good idea but I need something else.
I have the following table (inventory):
animal date quantity
dog 2015-01-01 400
cat 2015-01-01 300
dog 2015-01-02 402
rabbit 2015-01-01 500
cat 2015-01-02 304
rabbit 2015-01-02 508
rabbit 2015-01-03 524
rabbit 2015-01-04 556
rabbit 2015-01-05 620
rabbit 2015-01-06 748
By running this query:
SELECT a.animal, a.Date
AS actual_date, past_date.Date
AS past_date, (a.quantity - past_date.quantity)
AS quantity_diff
FROM inventory a
JOIN
(SELECT b.animal, b.date AS date1,
(SELECT MAX(c.date)
FROM inventory c
WHERE c.date < b.date AND c.animal = b.animal
GROUP BY c.animal)
AS date2
FROM inventory b)
AS original_date ON original_date.animal = a.animal
AND original_date.date1 = a.date
JOIN
inventory past_date
ON past_date.animal = a.animal
AND past_date.date = original_date.date2
I get this:
animal actual_date past_date quantity_diff
dog 2015-01-02 2015-01-01 2
cat 2015-01-02 2015-01-01 4
rabbit 2015-01-02 2015-01-01 8
rabbit 2015-01-03 2015-01-02 16
rabbit 2015-01-04 2015-01-03 32
rabbit 2015-01-05 2015-01-04 64
rabbit 2015-01-06 2015-01-05 128
What I want to get is this (see quantity_diff column):
animal quantity_diff
cat 4
cat NULL
dog 2
dog NULL
rabbit 8
rabbit 16
rabbit 32
rabbit 64
rabbit 128
rabbit NULL
http://sqlfiddle.com/#!9/c77d8/11
Upvotes: 5
Views: 1711
Reputation: 441
I have changed your query a bit which will get you the desired result and used LEFT JOIN on the tables:
SELECT a.animal,(a.quantity - past_date.quantity) AS quantity_diff
FROM inventory a
LEFT JOIN
(SELECT b.animal, b.date AS date1,
(SELECT MAX(c.date)
FROM inventory c
WHERE c.date < b.date AND c.animal = b.animal
GROUP BY c.animal
)
AS date2
FROM inventory b
)
AS original_date ON original_date.animal = a.animal
AND original_date.date1 = a.date
LEFT JOIN inventory past_date
ON past_date.animal = a.animal
AND past_date.date = original_date.date2
ORDER BY animal ,past_date.quantity ASC
RESULT IS :
cat (null)
cat 4
dog (null)
dog 2
rabbit (null)
rabbit 8
rabbit 16
rabbit 32
rabbit 64
rabbit 128
Upvotes: 1
Reputation: 4643
To make the query do what you want you need to put LEFT
before the JOIN
keywords, and add an ORDER BY
clause.
So the resulting query is:
SELECT a.animal, a.Date
AS actual_date, past_date.Date
AS past_date, (a.quantity - past_date.quantity)
AS quantity_diff
FROM inventory a
LEFT JOIN
(SELECT b.animal, b.date AS date1,
(SELECT MAX(c.date)
FROM inventory c
WHERE c.date < b.date AND c.animal = b.animal
GROUP BY c.animal)
AS date2
FROM inventory b)
AS original_date ON original_date.animal = a.animal
AND original_date.date1 = a.date
LEFT JOIN
inventory past_date
ON past_date.animal = a.animal
AND past_date.date = original_date.date2
ORDER BY a.animal asc, a.date asc
Upvotes: 1
Reputation: 921
Try this query:
SELECT L.animal,L.date,
(SELECT date FROM inventory WHERE animal=L.animal AND date<L.date ORDER BY date DESC LIMIT 1) AS 'past_date',
(L.quantity-(SELECT quantity FROM inventory WHERE animal=L.animal AND date<L.date ORDER BY date DESC LIMIT 1)) AS 'quantity_diff'
FROM inventory AS L
GROUP BY (CONCAT(L.animal,'-',L.date));
This query is going to search for each animal+date what is the most recent date before the current date. For example, for the first record:
dog 2015-01-01 400
The most recent date before '2015-01-01' is null, so there isn't anything to substract from the current quantity (400). For the second record:
dog 2015-01-02 402
The most recent date for current animal(dog), which it's before the current date('2015-01-02') is '2015-01-01', which has a quantity of 402, so the difference is 402-400=2. The process is the same for each animal.
Upvotes: 1
Reputation: 24960
The Question has changed a little bit, here is my current understanding of what you want.
CREATE TABLE inventory
(`animal` varchar(6), `date` date, `quantity` int);
INSERT INTO inventory
(`animal`, `date`, `quantity`)
VALUES
('dog', '2015-01-01', 400),
('cat', '2015-01-01', 300),
('dog', '2015-01-02', 402),
('rabbit', '2015-01-01', 500),
('cat', '2015-01-02', 304),
('rabbit', '2015-01-02', 508),
('rabbit', '2015-01-03', 524),
('rabbit', '2015-01-04', 556),
('rabbit', '2015-01-05', 620),
('rabbit', '2015-01-06', 748);
select animal,actual_date,past_date,quantity_diff
from
( SELECT a.animal, a.Date
AS actual_date, past_date.Date
AS past_date, (a.quantity - past_date.quantity)
AS quantity_diff,
1 as drewOrder
FROM inventory a
JOIN
(SELECT b.animal, b.date AS date1,
(SELECT MAX(c.date)
FROM inventory c
WHERE c.date < b.date AND c.animal = b.animal
GROUP BY c.animal)
AS date2
FROM inventory b)
AS original_date ON original_date.animal = a.animal
AND original_date.date1 = a.date
JOIN
inventory past_date
ON past_date.animal = a.animal
AND past_date.date = original_date.date2
union
select distinct animal,null,null,null,2 as drewOrder from inventory
) x
order by x.animal,x.drewOrder,x.actual_date;
+--------+-------------+------------+---------------+
| animal | actual_date | past_date | quantity_diff |
+--------+-------------+------------+---------------+
| cat | 2015-01-02 | 2015-01-01 | 4 |
| cat | NULL | NULL | NULL |
| dog | 2015-01-02 | 2015-01-01 | 2 |
| dog | NULL | NULL | NULL |
| rabbit | 2015-01-02 | 2015-01-01 | 8 |
| rabbit | 2015-01-03 | 2015-01-02 | 16 |
| rabbit | 2015-01-04 | 2015-01-03 | 32 |
| rabbit | 2015-01-05 | 2015-01-04 | 64 |
| rabbit | 2015-01-06 | 2015-01-05 | 128 |
| rabbit | NULL | NULL | NULL |
+--------+-------------+------------+---------------+
Upvotes: 1
Reputation: 1254
"Left outer Join" should solve your problem.
Something similar is already present in below question, please check Mike Parkhill's answer
SQL subtract two rows based on date and another column
Upvotes: 0