【问题标题】:mysql: difference between values in one columnmysql:一列中的值之间的差异
【发布时间】:2018-02-27 23:07:12
【问题描述】:

这个板在过去帮助了我几次。

我的挑战:我想得到一列中值之间的差异。

表格如下所示:

id  |  channel_id  |  timestamp   |  value
4515|    7         |1519771680000 |  7777
4518|    8         |1519772160000 |  6666
4520|    7         |1519772340000 |  8888
  • id:来自数据源的内部 ID。在某些情况下,它是订购的,在其他情况下则不是。我们不能下达这个命令。
  • channel_id:不同的数据源。
  • 时间戳:unix 时间戳。
  • 值:测量值。

我想做什么:

过滤器(例如 channel_id = 7)。 计算一个时间戳和下一个时间戳之间的差异。在这个例子中:8888-7777

我在另一个数据库上找到了解决方案,但由于 Windows 功能非常有限,我无法将其传输到 mysql。你们中有人知道如何获得可用于选择语句的解决方案吗?

谢谢和韩国 霍尔格

【问题讨论】:

  • 您可以根据时间戳对特定频道的行进行过滤和排名。然后加入它本身说 table1.rank = table2.rank + 1。然后你可以得到差异。您可能需要查看如何在 mysql 上进行排名,因为该功能在这里不像在 mysql 中那样工作。
  • 你能澄清Calculate the difference between one timestamp and the next one.的意思吗?您想要一个具有匹配通道 id 的记录和另一个具有不同时间戳的记录之间的 value 列之间的差异,对吗?
  • @clinomaniac:您好,排名和自我加入是我正在努力/试图开始工作但正在挣扎的事情。 (选择 .... (AT)rowid:=(AT)rowid+1 as rowid .. FROM ... (SELECT (AT)rowid:=0) as init, .... 但我不能在加入。
  • @Sloan Thrasher:“计算差异”:相同的通道 id、时间戳和直接前一个时间戳(下一个较低的时间戳)、值之间的差异。这就是我尝试做的。
  • @holgerabend Used_By_Already 提供的解决方案没有帮助吗?这似乎应该适用于您的情况。

标签: mysql window-functions


【解决方案1】:

您可以通过将表连接到自身来比较(即减去)两行:

SELECT
    a.channel_id,
    a.timestamp,
    b.timestamp,
    a.value - b.value as `difference`
FROM table a
JOIN table b
ON a.channel_id = b.channel_id and a.timestamp <> b.timestamp and a.value > b.value
GROUP BY a.channel_id
ORDER BY a.channel_id

【讨论】:

  • 我认为解决方案没有那么简单。如果价值下降怎么办?如果有多个值大于当前值怎么办?
  • @clinomaniac,你提出了一些好的观点,但根据 OP 在他们的问题中提出的内容,这至少是一个起点。
  • 嗨,值不会下降。它们保持原样或略有增加。因此时间戳会发生变化,而值会保持不变。
【解决方案2】:

您可以为此使用“相关子查询”,如下所示(also see this demo)。当 MySQL 实现诸如 LEAD() 之类的窗口函数时,您可以使用它们。

MySQL 5.6 架构设置

CREATE TABLE Table1
    (`id` int, `channel_id` int, `timestamp` bigint, `value` int)
;

INSERT INTO Table1
    (`id`, `channel_id`, `timestamp`, `value`)
VALUES
    (4515, 7, 1519771680000, 7777),
    (4518, 8, 1519772160000, 6666),
    (4520, 7, 1519772340000, 8888)
;

查询 1

select
      id
    , channel_id
    , timestamp
    , value
    , nxt_value
    , nxt_value - value as diff
from (
    select
          t1.id
        , t1.channel_id
        , t1.timestamp
        , t1.value
        , (select value from table1 as t2 
           where t2.channel_id = t1.channel_id
           and t2.timestamp > t1.timestamp
           order by t2.timestamp
           limit 1) nxt_value
    from table1 as t1
    ) as d

Results

|   id | channel_id |     timestamp | value | nxt_value |   diff |
|------|------------|---------------|-------|-----------|--------|
| 4515 |          7 | 1519771680000 |  7777 |      8888 |   1111 |
| 4518 |          8 | 1519772160000 |  6666 |    (null) | (null) |
| 4520 |          7 | 1519772340000 |  8888 |    (null) | (null) |

【讨论】:

  • 这行不通,因为我无法更改表格的结构。
  • 表结构没有改变。结果有几列,但您可以从中选择您需要的内容。
  • @holgerabend 不需要更改表结构。建议的查询包括新列(nxt_value & diff),但它们只是在您运行查询时计算出来的。跨度>
【解决方案3】:

从 MySQL 8 开始,您可以使用window functions,在这种情况下您的查询将如下所示:

SELECT
  id, channel_id, timestamp, value,
  value - LAG(value, 1, 0) OVER (PARTITION BY channel_id ORDER BY timestamp) difference
FROM my_table

【讨论】:

    【解决方案4】:

    感谢大家的支持。我尝试了很多,并基于存储过程创建了“我的”解决方案。它的性能不如预期,但它提供了所需的值。

    代码在循环中运行,脚本执行中的重复次数最大,以避免无休止的步骤:)

    
    #Auswahl größer CH10-Wert
    set @var_max_ch10vz =
        (
        select max(data.timestamp)
        from volkszaehler.data 
        where data.channel_id=10
        )
    ;
    #Auswahl kleinster offener Wert aus SBFSPOT
    set @var_min_sbfspot = 
        (
        select min(data.timestamp_unix*1000)
        from sbfspot_u.data
        where 
            data.timestamp_vzjoin is null 
            and data.timestamp_unix >1522096327
            and data.timestamp_unix*1000 < @var_max_ch10vz
        )
    ;
    #Abgleich gegen VZ von unten
    set @var_max_vz =
        (
        select min(data.timestamp)
        from volkszaehler.data 
        where data.channel_id=10 and data.timestamp >= @var_min_sbfspot
        )
    ;
    #Abgleich gegen VZ von oben
    set @var_min_vz =
        (
        select max(data.timestamp)
        from volkszaehler.data 
        where data.channel_id=10 and data.timestamp <= @var_min_sbfspot
        )
    ;
    #Auswahl join Zeitstempel
    set @vz_join_timestamp =
        (
            select tmp.uxtimestamp 
            from (
                select @var_max_vz as uxtimestamp, abs(@var_min_sbfspot-@var_max_vz) as diff
                UNION
                select @var_min_vz as uxtimestamp, abs(@var_min_sbfspot-@var_min_vz) as diff
                ) tmp
            order by tmp.diff asc
            limit 1
        )
    ;
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2022-01-16
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-07-12
      • 2016-10-11
      • 1970-01-01
      相关资源
      最近更新 更多