2012-04-11 54 views
0

一直試圖圍繞如何在此表中設置Duration包括我的頭,與一個查詢,這是行的時間戳和前一行的值爲SkillTargetID。我發現了一些類似的問題(this one特別有用),但他們都能夠預測第二行的距離,例如,基於月份值。對於我的每一行數據,其「姐妹」行可能與它相鄰,或者不相鄰。設置列之間的差值行之間的行數不確定的行之間的差異

這裏是我的表在這個例子中的簡化版本:

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值將始終大於或等於到上一行,如這個示例數據所示。具有相同UTC_DateTime的不同SkillTargetID值的順序不可預測,並且許多行將具有相同的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); 

感謝您提前幫忙!

回答

1

你可以通過實現@ mysql變量來簡化它。預先查詢以獲得一個ID,以及與它關聯的下一個ID,然後對原始表TWICE(不同的別名)進行連接以獲得適當的值,然後執行所需的任何計算...因此,「最後一個ID 「列是無論@WasLastID值如果它在相同的技能目標ID資格。如果不是,它會被設置回零。在應用TEST之後,@WasLastID獲取當前記錄的ID作爲下一個條目測試的BASIS。

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 

通過將應用到結果之前任何@變量設置的順序處理的,所以上面的查詢會在本質上創建以下結果確保所有技能目標應用@最後一個目標時,正確排序比較...

+----+---------------+--------------+--------+------------+---------------+ 
    | 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 
+0

我最後做的大部分的這個代碼,而不是SQL,但是喲你的想法確實奏效 - 我測試了它。不過,我可能會將這個想法用於其他方面。感謝您抽出寶貴的時間。 – aparker 2012-04-25 20:18:04