SQL how to subtract result row 1 from row 2, row 2 from row 3

徘徊边缘 提交于 2021-02-08 08:35:56

问题


How do I subtract row 1 from row 2 and row 2 from row 3, etc. in MySQL? The table i am pulling my data from contains multiple products and all products have multiple prices (on different dates)

The code i am working with:

 SELECT 
        orderline_sales.product_name,
        orderline_sales.price
    FROM
        orderline_sales         
    GROUP BY price
    HAVING orderline_sales.product_name = 'Ibuprofen';

The result I am getting:

|---------------------|------------------|
|      product_name   |     price        |
|---------------------|------------------|
|       Ibuprofen     |      30.20       |
|---------------------|------------------|
|       Ibuprofen     |      32.20       |
|---------------------|------------------|
|       Ibuprofen     |      35.20       |
|---------------------|------------------|

The result I want:

|---------------------|------------------|------------------|
|      product_name   |     price        |   price_change   |
|---------------------|------------------|------------------|
|       Ibuprofen     |      30.20       |         0        |
|---------------------|------------------|------------------|
|       Ibuprofen     |      32.20       |         2        |
|---------------------|------------------|------------------|
|       Ibuprofen     |      35.20       |         3        |
|---------------------|------------------|------------------|

回答1:


You probably want to look into MySQL's user defined variables, and then you probably want to do something like this:

SET @prev := NULL;
SELECT
    DATE(created_at),
    price - COALESCE(@prev, price) AS price_change,
    name,
    (@prev := price) AS price FROM (
        SELECT * FROM items ORDER BY DATE(created_at)
    ) t1
GROUP BY
    name, price, DATE(created_at)
HAVING name = 'Ibuprofen'
ORDER BY DATE(created_at);
Query OK, 0 rows affected (0.00 sec)

I haven't checked syntax so it might be a little off but that is the general idea. Note that I added date so that you can order by it, otherwise the results may be meaningless.

EDIT:

Just ran this on my machine:

SET @prev := NULL;
SELECT
    DATE(created_at),
    price - COALESCE(@prev, price) AS price_change,
    name,
    (@prev := price) AS price FROM (
        SELECT * FROM items ORDER BY DATE(created_at)
    ) t1
GROUP BY
    name, price, DATE(created_at)
HAVING name = 'Ibuprofen'
ORDER BY DATE(created_at);

Query OK, 0 rows affected (0.00 sec)

+------------------+--------------+-----------+-------+
| DATE(created_at) | price_change | name      | price |
+------------------+--------------+-----------+-------+
| 2018-12-10       |            0 | Ibuprofen |   110 |
| 2018-12-13       |          -10 | Ibuprofen |   100 |
| 2018-12-13       |           20 | Ibuprofen |   120 |
+------------------+--------------+-----------+-------+

3 rows in set, 1 warning (0.00 sec)

SELECT * FROM items;
+----+-------+----------------+---------------------+
| id | price | name           | created_at          |
+----+-------+----------------+---------------------+
|  8 |   100 | Ibuprofen      | 2018-12-13 12:52:35 |
|  9 |   110 | Ibuprofen      | 2018-12-10 12:12:12 |
| 10 |   120 | Ibuprofen      | 2018-12-13 12:52:35 |
| 11 |  1000 | Something else | 2018-12-13 13:01:19 |
+----+-------+----------------+---------------------+

4 rows in set (0.00 sec)



回答2:


Maybe something like this could work ?

DROP TABLE IF EXISTS test;

CREATE TABLE test (
product_name text,
price numeric
);

INSERT INTO test VALUES 
('ibuprofen', 30.20),
('ibuprofen', 32.20),
('ibuprofen', 35.20);


SELECT DISTINCT t.product_name, t.current_price - t.previous_price AS price_change
FROM (SELECT te.product_name, te.price AS current_price, 
         LAG(te.price) over w  AS previous_price, 
         row_number() over w AS rn
         FROM test AS te 
         WINDOW w AS (ORDER BY te.product_name, te.price)
         ) AS t
WHERE t.product_name = 'ibuprofen'
AND t.rn <> 1
ORDER BY t.product_name, price_change;

This Query returns following result:

 product_name | price_change 
--------------+--------------
 ibuprofen    |         0.00
 ibuprofen    |         2.00
 ibuprofen    |         3.00



回答3:


Let's assume the original purpose was to track price changes (time/id). Assuming the GROUP BY was there to eliminate rows where price has not changed. You could do following (variation of @dave 's answer):

SELECT product_name, price, cast( ifnull(price_change,0) as decimal(6,2)) as price_change
FROM (
SELECT
    product_name,
    price - @prev AS price_change,
    (@prev := price) AS price
FROM
    orderline_sales
    JOIN (SELECT @prev := null) as j
WHERE orderline_sales.product_name = 'Ibuprofen' 
ORDER BY id
) as q
WHERE price_change is null or price_change!=0;

The difference to @dave's answer is the removal of incorrect use of GROUP BY.

See db-fiddle.



来源:https://stackoverflow.com/questions/53769621/sql-how-to-subtract-result-row-1-from-row-2-row-2-from-row-3

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!