2012-04-11 2 views
0

Ich habe versucht, in dieser Tabelle Duration zu setzen, mit einer einzigen Abfrage, das ist der Unterschied zwischen dem Timestamp der Zeile und die vorherige Reihe der gleichen SkillTargetID Wert. Ich fand bereits einige ähnliche Fragen (this one war besonders hilfreich), aber sie alle waren in der Lage zu sagen, wie weit die zweite Reihe entfernt ist, zum Beispiel basierend auf einem Monat. Für jede Zeile meiner Daten könnte die "Schwester" -Reihe daneben liegen oder nicht. HierSetzen einer Spalte auf einen Unterschied zwischen Zeilen Werte mit einer unbestimmten Anzahl von Zeilen zwischen ihnen

ist eine verkleinerte Version meiner Tabelle für dieses Beispiel:

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

Die Basisdaten in der Tabelle zu dieser Regel hält: Wenn nach dem id bestellt, werden die Werte von UTC_DateTime wird immer größer oder gleich zur vorherigen Reihe, wie diese Beispieldaten zeigen. Die Reihenfolge der verschiedenen SkillTargetID Werte mit der gleichen UTC_DateTime ist nicht vorhersehbar, und viele Zeilen haben die gleichen UTC_DateTime und SkillTargetID (wie 16 und 17).

Der beste Versuch, den ich mit so gekommen sind weit enthält eine Unterabfrage der vorherigen zugehörigen Zeile zu finden, wenn es vorhanden ist (ich die zweite UTC_DateTime so kann auch ausgewählt Sie sehen, was abgezogen wird):

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

Offensichtlich wird ein UPDATE wie dieses schnell böse, wenn dieser Tisch wächst. Das ist alles, was ich tun kann, bevor im Kreis wieder um:

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 

Welche anderen Möglichkeiten habe ich?

Hier ist die Testdatum war ich mit:

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); 

BONUS - Ist es möglich, dies zu tun, während neue mehrreihigen Einfügen von Daten, wenn sie die id bereits bestellt enthalten? Wie zum Beispiel:

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

Danke für die Hilfe vor der Zeit!

Antwort

1

Sie könnten es wahrscheinlich viel einfacher haben, indem Sie @ mysql-Variablen implementieren. Pre-Abfrage, um eine ID zu erhalten, und die ID der nächsten zugeordneten, dann eine Verbindung zu der ursprünglichen Tabelle ZWEIMAL (verschiedene Aliase), um richtige Werte zu haben, dann tun, was calc Sie brauchen ... Also, die "LastID "Spalte ist, was auch immer der Wert für @WasLastID war, wenn sie innerhalb der gleichen Qualifikationsziel-ID-Qualifikation war. Wenn nicht, wird es auf Null zurückgesetzt. Nachdem dieser Test angewendet wurde, erhält die @WasLastID die ID des aktuellen Datensatzes als BASIS des nächsten Eintrags.

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 

Die Bestellung wird an das vor einem der @ Variablen Ergebnis angewandt werden verarbeitet, so dass die obige Abfrage im Wesentlichen würde folgendes Ergebnis sicherzustellen, dass alle Fähigkeiten Ziele erstellen richtig sequenziert werden, wenn die @ letztes Ziel der Anwendung Vergleiche ...

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

Nun sind alle, die gesagt und Probe zur Verfügung gestellt, können Sie dann auf diese erweitern wie ...

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

ich die meisten dieser in Code anstelle von SQL-ended zu tun, aber yo Deine Idee funktioniert - ich habe es getestet.Ich werde wahrscheinlich diese Idee für andere Dinge verwenden können. Danke, dass du dir die Zeit genommen hast. – aparker

Verwandte Themen