MySQL-更新行与当前行和前一行之间的列差异

发布于 2024-12-12 00:39:43 字数 3402 浏览 0 评论 0原文

我有一个具有以下结构的表 data_temp:

CREATE TABLE `data_temp` (
  `id` bigint(20) NOT NULL,
  `deviceid` int(11) NOT NULL,
  `registeraddress` int(11) NOT NULL,
  `value` decimal(20,9) NOT NULL,
  `time` datetime NOT NULL,
  `value_diff` decimal(20,9) NOT NULL DEFAULT '0.000000000',
  `time_diff` bigint(20) NOT NULL DEFAULT '0'
)

id 是唯一的但不连续。
deviceid/registeraddress/time 的记录是唯一的。
插入的记录包含 id、deviceid、registeraddress、value 和 time 的值。
我想计算 value_diff 和 time_diff ,它们是插入的记录与对应于 deviceid 和 registeraddress 的上一条记录之间的值差以及以秒为单位的时间差。

该表已经有很多记录,但都没有计算 value_diff 和 time_diff ,因此我想用这些值更新表中的现有数据。

这是一些示例数据:

id,  deviceid, registeraddress, value,time    
11102116190949258, 101, 856, 34.000000000, 2011-10-21 16:19:00
11102116240432553, 101, 856, 38.000000000, 2011-10-21 16:24:00
11102116290249672, 101, 856, 44.000000000, 2011-10-21 16:29:00
11102116340121243, 101, 856, 54.000000000, 2011-10-21 16:34:00
11102116390025291, 101, 856, 57.000000000, 2011-10-21 16:39:00
11102116440032519, 101, 856, 63.000000000, 2011-10-21 16:44:00

我可以在表上执行以下选择,它将列出我想要的数据:

SELECT 
    r_B.deviceid, 
    r_B.registeraddress,
    r_B.value,
    r_B.time, 
    COALESCE(TIME_TO_SEC(TIMEDIFF(r_B.time,r_A.time)), 0) AS time_diff,
    COALESCE(r_B.value-r_A.value, 0) AS value_diff
FROM data_temp r_B
    LEFT OUTER JOIN data_temp r_A
    ON r_B.deviceid = r_A.deviceid 
        AND r_B.registeraddress = r_A.registeraddress 
        AND r_B.time > r_A.time
WHERE NOT EXISTS 
    (
        SELECT r_C.time 
        FROM data_temp r_C
        WHERE r_C.deviceid = r_C.deviceid 
            AND r_C.registeraddress = r_C.registeraddress 
            AND r_C.time > r_A.time 
            AND r_C.time < r_B.time
    )
ORDER BY r_B.deviceid, r_B.registeraddress, r_B.time

结果:

id,  deviceid, registeraddress, value, time, value_diff, time_diff
11102116190949258, 101, 856, 34.000000000, 2011-10-21 16:19:00, 0,   0.000000000
11102116240432553, 101, 856, 38.000000000, 2011-10-21 16:24:00, 300, 4.000000000
11102116290249672, 101, 856, 44.000000000, 2011-10-21 16:29:00, 300, 6.000000000
11102116340121243, 101, 856, 54.000000000, 2011-10-21 16:34:00, 300, 10.000000000
11102116390025291, 101, 856, 57.000000000, 2011-10-21 16:39:00, 300, 3.000000000
11102116440032519, 101, 856, 63.000000000, 2011-10-21 16:44:00, 300, 6.000000000

我已经尝试了几天来找出如何编写相应的更新。我已经尝试过以下操作:

UPDATE data_temp r_B
    LEFT OUTER JOIN data_temp r_A
    ON r_B.deviceid = r_A.deviceid 
        AND r_B.registeraddress=r_A.registeraddress 
        AND r_B.time > r_A.time
SET r_B.time_diff = COALESCE(TIME_TO_SEC(TIMEDIFF(r_B.time,r_A.time)), 0),
    r_B.value_diff = COALESCE(r_B.value-r_A.value, 0)
WHERE NOT EXISTS 
    (
        SELECT r_C.time 
        FROM data_temp r_C 
        WHERE r_C.deviceid = r_B.deviceid 
            AND r_C.registeraddress = r_B.registeraddress 
            AND r_C.time > r_A.time 
            AND r_C.time < r_B.time
    )

但是当然会遇到稍微令人沮丧的 MySQL 错误:

Error Code: 1093
You can't specify target table 'r_B' for update in FROM clause

这里的问题在于末尾的 WHERE 子句。更新在没有该子句的情况下工作,但给出了错误的结果(所有记录都根据当前记录和最旧记录之间的差异进行更新,而不是先前记录)。除了 WHERE 子句之外,语句中的其他所有内容都有效。

我已经研究这个问题很长一段时间了,但还没有找到好的解决方案,因此我们将不胜感激。

I have a table data_temp with the following structure:

CREATE TABLE `data_temp` (
  `id` bigint(20) NOT NULL,
  `deviceid` int(11) NOT NULL,
  `registeraddress` int(11) NOT NULL,
  `value` decimal(20,9) NOT NULL,
  `time` datetime NOT NULL,
  `value_diff` decimal(20,9) NOT NULL DEFAULT '0.000000000',
  `time_diff` bigint(20) NOT NULL DEFAULT '0'
)

id is unique but not contiguous.
Records are unique for deviceid/registeraddress/time.
Records are inserted which contain values for id,deviceid,registeraddress,value and time.
I want to calculate value_diff and time_diff which are the difference in value between the inserted record and the previous record corresponding to deviceid and registeraddress and difference in time in seconds.

The table already has a lot of records all without the value_diff and time_diff calculated so I want to update the existing data in the table with these values.

Here is some sample data:

id,  deviceid, registeraddress, value,time    
11102116190949258, 101, 856, 34.000000000, 2011-10-21 16:19:00
11102116240432553, 101, 856, 38.000000000, 2011-10-21 16:24:00
11102116290249672, 101, 856, 44.000000000, 2011-10-21 16:29:00
11102116340121243, 101, 856, 54.000000000, 2011-10-21 16:34:00
11102116390025291, 101, 856, 57.000000000, 2011-10-21 16:39:00
11102116440032519, 101, 856, 63.000000000, 2011-10-21 16:44:00

I can do the following select on the table which will list the data that I want:

SELECT 
    r_B.deviceid, 
    r_B.registeraddress,
    r_B.value,
    r_B.time, 
    COALESCE(TIME_TO_SEC(TIMEDIFF(r_B.time,r_A.time)), 0) AS time_diff,
    COALESCE(r_B.value-r_A.value, 0) AS value_diff
FROM data_temp r_B
    LEFT OUTER JOIN data_temp r_A
    ON r_B.deviceid = r_A.deviceid 
        AND r_B.registeraddress = r_A.registeraddress 
        AND r_B.time > r_A.time
WHERE NOT EXISTS 
    (
        SELECT r_C.time 
        FROM data_temp r_C
        WHERE r_C.deviceid = r_C.deviceid 
            AND r_C.registeraddress = r_C.registeraddress 
            AND r_C.time > r_A.time 
            AND r_C.time < r_B.time
    )
ORDER BY r_B.deviceid, r_B.registeraddress, r_B.time

result:

id,  deviceid, registeraddress, value, time, value_diff, time_diff
11102116190949258, 101, 856, 34.000000000, 2011-10-21 16:19:00, 0,   0.000000000
11102116240432553, 101, 856, 38.000000000, 2011-10-21 16:24:00, 300, 4.000000000
11102116290249672, 101, 856, 44.000000000, 2011-10-21 16:29:00, 300, 6.000000000
11102116340121243, 101, 856, 54.000000000, 2011-10-21 16:34:00, 300, 10.000000000
11102116390025291, 101, 856, 57.000000000, 2011-10-21 16:39:00, 300, 3.000000000
11102116440032519, 101, 856, 63.000000000, 2011-10-21 16:44:00, 300, 6.000000000

I have been trying for a couple of days now to work out how to write the corresponding update. I have tried the following:

UPDATE data_temp r_B
    LEFT OUTER JOIN data_temp r_A
    ON r_B.deviceid = r_A.deviceid 
        AND r_B.registeraddress=r_A.registeraddress 
        AND r_B.time > r_A.time
SET r_B.time_diff = COALESCE(TIME_TO_SEC(TIMEDIFF(r_B.time,r_A.time)), 0),
    r_B.value_diff = COALESCE(r_B.value-r_A.value, 0)
WHERE NOT EXISTS 
    (
        SELECT r_C.time 
        FROM data_temp r_C 
        WHERE r_C.deviceid = r_B.deviceid 
            AND r_C.registeraddress = r_B.registeraddress 
            AND r_C.time > r_A.time 
            AND r_C.time < r_B.time
    )

But of course get the slightly frustrating MySQL error:

Error Code: 1093
You can't specify target table 'r_B' for update in FROM clause

The problem here is with the WHERE clause at the end. The update works without the clause but gives the wrong result (all records are updated with the difference between the current and the oldest record not the previous record). Everything else in the statement works except the WHERE clause.

I have been researching this for quite a while now and haven't found a good solution so any help would be appreciated.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。
列表为空,暂无数据
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文