0

一直试图围绕如何Duration在此表中进行设置,使用单个查询,即行的时间戳与相同SkillTargetID值的前一行之间的差异。我已经发现了一些类似的问题(这个问题特别有帮助),但是他们都能够预测第二行的距离,例如,基于一个月的值。对于我的数据的每一行,它的“姐妹”行可能与它相邻,也可能不相邻。

这是此示例中我的表的简化版本:

mysql> select * from testdur order by id;
+----+---------------+--------------+----------+
| id | SkillTargetID | UTC_DateTime | Duration |
+----+---------------+--------------+----------+
|  1 |          5000 |   1323719341 |     NULL |
|  2 |          5010 |   1323719341 |     NULL |
|  3 |          5000 |   1323719342 |     NULL |
|  4 |          5010 |   1323719342 |     NULL |
|  5 |          5000 |   1323719343 |     NULL |
|  6 |          5055 |   1323719345 |     NULL |
|  7 |          5010 |   1323719350 |     NULL |
|  8 |          5010 |   1323719441 |     NULL |
|  9 |          5010 |   1323719444 |     NULL |
| 10 |          5000 |   1323719445 |     NULL |
| 11 |          5055 |   1323719445 |     NULL |
| 12 |          5060 |   1323719445 |     NULL |
| 13 |          5000 |   1323719445 |     NULL |
| 14 |          5010 |   1323719445 |     NULL |
| 15 |          5060 |   1323719446 |     NULL |
| 16 |          5000 |   1323719460 |     NULL |
| 17 |          5000 |   1323719460 |     NULL |
| 18 |          5060 |   1323719500 |     NULL |
+----+---------------+--------------+----------+

表中的基本数据遵循此规则:当按 排序时id, 的值UTC_DateTime将始终大于或等于前一行,如此示例数据所示。相同的不同SkillTargetID值的顺序UTC_DateTime是不可预测的,很多行会有相同的UTC_DateTimeSkillTargetID(例如16和17)。

到目前为止,我想出的最佳尝试包括一个子查询来查找前一个关联的行,如果它存在的话(我还选择了第二个UTC_DateTime,这样你就可以看到被减去的内容):

SELECT
 t.id,
 t.SkillTargetID,
 t.UTC_DateTime,
 t2.UTC_DateTime AS UTC_DateTime2,
 (CASE WHEN t2.UTC_DateTime IS NULL THEN 0 ELSE t.UTC_DateTime - t2.UTC_DateTime END) AS Duration
FROM testdur t LEFT JOIN testdur t2
 ON t.SkillTargetID = t2.SkillTargetID
 AND t2.id = (
  SELECT id FROM testdur
  WHERE SkillTargetID = t.SkillTargetID AND id < t.id
  ORDER BY id DESC
  LIMIT 1 )
ORDER BY t.id;
+----+---------------+--------------+---------------+----------+
| id | SkillTargetID | UTC_DateTime | UTC_DateTime2 | Duration |
+----+---------------+--------------+---------------+----------+
|  1 |          5000 |   1323719341 |          NULL |        0 |
|  2 |          5010 |   1323719341 |          NULL |        0 |
|  3 |          5000 |   1323719342 |    1323719341 |        1 |
|  4 |          5010 |   1323719342 |    1323719341 |        1 |
|  5 |          5000 |   1323719343 |    1323719342 |        1 |
|  6 |          5055 |   1323719345 |          NULL |        0 |
|  7 |          5010 |   1323719350 |    1323719342 |        8 |
|  8 |          5010 |   1323719441 |    1323719350 |       91 |
|  9 |          5010 |   1323719444 |    1323719441 |        3 |
| 10 |          5000 |   1323719445 |    1323719343 |      102 |
| 11 |          5055 |   1323719445 |    1323719345 |      100 |
| 12 |          5060 |   1323719445 |          NULL |        0 |
| 13 |          5000 |   1323719445 |    1323719445 |        0 |
| 14 |          5010 |   1323719445 |    1323719444 |        1 |
| 15 |          5060 |   1323719446 |    1323719445 |        1 |
| 16 |          5000 |   1323719460 |    1323719445 |       15 |
| 17 |          5000 |   1323719460 |    1323719460 |        0 |
| 18 |          5060 |   1323719500 |    1323719446 |       54 |
+----+---------------+--------------+---------------+----------+

显然,随着这个表的增长,像这样的 UPDATE 会变得非常糟糕。这是我在绕圈子之前能想到的全部:

UPDATE testdur t SET t.Duration = t.UTC_DateTime - (
 SELECT UTC_DateTime FROM testdur
 WHERE SkillTargetID = t.SkillTargetID AND id < t.id
 ORDER BY id DESC LIMIT 1 );
ERROR 1093 (HY000): You can't specify target table 't' for update in FROM clause

我还有什么其他选择?

这是我使用的测试数据:

CREATE TABLE `testdur` (
  `id` int(10) unsigned NOT NULL AUTO_INCREMENT,
  `SkillTargetID` int(10) unsigned NOT NULL,
  `UTC_DateTime` int(10) unsigned NOT NULL,
  `Duration` int(10) unsigned DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1;
INSERT INTO testdur (SkillTargetID,UTC_DateTime) VALUES (5000,1323719341),(5010,1323719341),(5000,1323719342),(5010,1323719342),(5000,1323719343),(5055,1323719345),(5010,1323719350),(5010,1323719441),(5010,1323719444),(5000,1323719445),(5055,1323719445),(5060,1323719445),(5000,1323719445),(5010,1323719445),(5060,1323719446),(5000,1323719460),(5000,1323719460),(5060,1323719500);

奖励 - 如果已经包含已订购的新多行数据,是否可以在插入新的多行数据时执行此操作id?比如期间:

INSERT INTO testdur (id,SkillTargetID,UTC_DateTime) VALUES
(19,5010,1323719505),
(20,5055,1323719510);

提前感谢您的帮助!

4

1 回答 1

1

通过实现@mysql 变量,您可能会更简化它。预查询以获取 ID,以及与之关联的下一个 ID,然后连接到原始表 TWICE(不同的别名)以获得正确的值,然后执行您需要的任何计算......所以,“LastID " 列是 @WasLastID 的任何值,如果它在相同的技能目标 ID 资格范围内。如果不是,则将其设置回零。应用 TEST 之后,@WasLastID 获取当前记录的 ID 作为下一个条目测试的基础。

select
      t.id,
      t.SkillTargetID,
      t.UTC_DateTime,
      t.UTC_DateTime2,
      if( @WasLastTarget = t.SkillTargetID, @WasLastID, 0 ) LastID,
      @WasLastID := t.ID as tmpLastID,
      @WasLastTarget := t.SkillTargetID as tmpLastTarget
   from
      testdur t,
      ( select @WasLastID = 0,
               @WasLastTarget := 0 ) sqlvars
   order by
      t.skillTargetID,
      t.id

order by 将在处理任何 @ 变量之前应用于结果集,因此上述查询实质上将创建以下结果,以确保在应用 @last 目标比较时所有技能目标都正确排序...

    +----+---------------+--------------+--------+------------+---------------+
    | id | SkillTargetID | UTC_DateTime | LastID |  tmpLastID | tmpLastTarget |
    +----+---------------+--------------+--------+------------+---------------+
    |  1 |          5000 |   1323719341 |     0  |      1     | 5000 
    |  3 |          5000 |   1323719342 |     1  |      3     | 5000
    |  5 |          5000 |   1323719343 |     3  |      5     | 5000
    | 10 |          5000 |   1323719445 |     5  |     10     | 5000
    | 13 |          5000 |   1323719445 |    10  |     13     | 5000
    | 16 |          5000 |   1323719460 |    13  |     16     | 5000
    | 17 |          5000 |   1323719460 |    16  |     17     | 5000
-- BREAK BETWEEN SKILL TARGET...
    |  2 |          5010 |   1323719341 |     0  |      2     | 5010
    |  4 |          5010 |   1323719342 |     2  |      4     | 5010
    |  7 |          5010 |   1323719350 |     4  |      7     | 5010
    |  8 |          5010 |   1323719441 |     7  |      8     | 5010
    |  9 |          5010 |   1323719444 |     8  |      9     | 5010
    | 14 |          5010 |   1323719445 |     9  |     14     | 5010
-- BREAK BETWEEN SKILL TARGET...
    |  6 |          5055 |   1323719345 |     0  |      6     | 5055
    | 11 |          5055 |   1323719445 |     6  |     11     | 5055
-- BREAK BETWEEN SKILL TARGET...
    | 12 |          5060 |   1323719445 |     0  |     12     | 5060
    | 15 |          5060 |   1323719446 |    12  |     15     | 5060
    | 18 |          5060 |   1323719500 |    15  |     18     | 5060
    +----+---------------+--------------+--------+------------+---------------+

现在,所有所说的和提供的样本,然后您可以对其进行扩展,例如...

select
      PreQuery.*,
      CASE WHEN t1.UTC_DateTime IS NULL THEN 0 
           ELSE t2.UTC_DateTime - t1.UTC_DateTime END) AS Duration
   from
      ( above full select query ) as PreQuery
         LEFT JOIN testdur t1
            on PreQuery.ID = t1.ID
         LEFT JOIN testdur t2
            on PreQuery.LastID = t2.ID
于 2012-04-11T14:16:00.193 回答