【问题标题】:SQL how to subtract result row 1 from row 2, row 2 from row 3SQL如何从第2行中减去结果第1行,从第3行中减去第2行
【发布时间】:2018-12-13 20:30:07
【问题描述】:

如何在 MySQL 中从第 2 行中减去第 1 行,从第 3 行中减去第 2 行等? 我从中提取数据的表包含多个产品,并且所有产品都有多个价格(在不同日期)

我正在使用的代码:

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

我得到的结果:

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

我想要的结果:

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

【问题讨论】:

  • 您选择 2 列 orderline_sales.product_name, orderline_sales.price 并获得 2 列。如果你需要 3,SELECT 3.
  • @Alex 这根本没用,考虑到他需要从上一列进行更改,他会为第三列选择什么。这是可行的,但肯定不是很明显
  • @dave 他的查询本身就很糟糕。 GROUP BY price 至少应该是 GROUP BY product_name, price。并且预期结果没有提供任何关于为什么数据应该包含额外列以及应该如何计算的解释。对我来说,重点是 OP 并不真正理解他自己的查询。
  • 我建议您阅读this 并提供示例数据。
  • 并添加到@Alex 的注释 SQL 定义为无序,因此 MySQL 不使用 ORDER BY 不知道哪一行是 1、2 或 3 .. 即使旧的 MySQL 版本自动排序 @ 987654330@ 查询 MySQL 5.7+ 中删除了此功能

标签: mysql calculated-columns correlated-subquery


【解决方案1】:

您可能想要查看 MySQL 的 user defined variables,然后您可能想要执行以下操作:

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)

我没有检查语法,所以它可能有点偏离,但这是一般的想法。请注意,我添加了日期,以便您可以按日期订购,否则结果可能毫无意义。

编辑:

刚刚在我的机器上运行了这个:

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)

【讨论】:

  • 你在 OP 中哪里看到了date
  • @Alex 我没有这就是为什么我说“请注意我添加了日期,以便您可以按它订购,否则结果可能毫无意义。”
  • 即使有日期也没有意义。您是否希望在同一个 date 中只存在一个价格?还是您希望datedatetime?您的方法仍然不正确或不清楚。我明白你在做什么。但我认为你只是越来越混淆 OP :-)
  • :-) 非常聪明的数据集2018-12-13 12:52:35 ;-) 并且在每组中都有一个记录 - 展示了我认为很少的场景。
  • 我在这里同意@Alex .. 除了HAVING name = 'Ibuprofen' 是关系,在这种情况下,使用WHERE name = 'Ibuprofen' 的“相同”,没有充分的理由你应该使用GROUP BY 来“ unduplicate" GROUP BY 旨在使用您在查询中未使用 anny 的聚合函数。您应该使用旨在取消重复的 DISTINCT
【解决方案2】:

也许这样的事情可以工作?

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;

此查询返回以下结果:

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

【讨论】:

  • 我喜欢这里提到的LAG()。是否仅从 MySQL 5.7 开始可用?
【解决方案3】:

假设最初的目的是跟踪价格变化(时间/id)。假设 GROUP BY 是为了消除价格没有变化的行。您可以执行以下操作(@dave 答案的变体):

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;

与@dave 答案的不同之处在于删除了GROUP BY 的错误使用。

db-fiddle

【讨论】:

  • @Alex,正如所说的,行的顺序可能是有的,否则整个问题就没有意义了。定义顺序的列是 datetime / id 或任何无关紧要的东西。如果列没有顺序,则该问题没有正确答案。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-08-13
  • 2011-03-30
  • 1970-01-01
  • 2015-06-29
相关资源
最近更新 更多