Frage

Am Suche eine einzelne Abfrage, die folgenden Informationen in der Tabelle konvertieren

name:time    :state
a   :10:00 AM:login
b   :10:05 AM:login
a   :10:06 AM:chatting
a   :10:08 AM:Idle
b   :10:11 AM:chatting
a   :10:10 AM:Logout
b   :10:12 AM:Logout

, um so etwas wie dies (wegen des Zeitbereiches von 10.00 bis 10.15 Uhr als Abfragezeitraum)

name: State    :Duration
a   : chatting :2 Minutes 
a   : Idle     :2 Minutes
b   : chatting :1 Minute

Kann dies nur unter Verwendung von SQL getan? Ist mit Informix Version 11.5

War es hilfreich?

Lösung

Es kann in einer einzigen SQL-Anweisung erfolgen. Hier ist der Beweis.

Setup

CREATE TEMP TABLE eventtable
(
    name CHAR(3) NOT NULL,
    time DATETIME HOUR TO MINUTE NOT NULL,
    state CHAR(8) NOT NULL
);

INSERT INTO eventtable(name, time, state) VALUES('a', '10:00', 'login');
INSERT INTO eventtable(name, time, state) VALUES('b', '10:05', 'login');
INSERT INTO eventtable(name, time, state) VALUES('a', '10:06', 'chatting');
INSERT INTO eventtable(name, time, state) VALUES('a', '10:08', 'Idle');
INSERT INTO eventtable(name, time, state) VALUES('b', '10:11', 'chatting');
INSERT INTO eventtable(name, time, state) VALUES('a', '10:10', 'Logout');
INSERT INTO eventtable(name, time, state) VALUES('b', '10:12', 'Logout');
INSERT INTO eventtable(name, time, state) VALUES('c', '10:01', 'login');
INSERT INTO eventtable(name, time, state) VALUES('c', '10:02', 'chatting');
INSERT INTO eventtable(name, time, state) VALUES('c', '10:03', 'Idle');
INSERT INTO eventtable(name, time, state) VALUES('c', '10:04', 'Logout');
INSERT INTO eventtable(name, time, state) VALUES('c', '10:05', 'Idle');
INSERT INTO eventtable(name, time, state) VALUES('c', '10:06', 'Logout');
INSERT INTO eventtable(name, time, state) VALUES('c', '10:07', 'Idle');
INSERT INTO eventtable(name, time, state) VALUES('c', '10:08', 'Logout');
INSERT INTO eventtable(name, time, state) VALUES('c', '10:09', 'login');
INSERT INTO eventtable(name, time, state) VALUES('c', '10:11', 'chatting');
INSERT INTO eventtable(name, time, state) VALUES('c', '10:12', 'Idle');
INSERT INTO eventtable(name, time, state) VALUES('c', '10:13', 'chatting');
INSERT INTO eventtable(name, time, state) VALUES('c', '10:14', 'Idle');
INSERT INTO eventtable(name, time, state) VALUES('c', '10:15', 'Logout');

Die richtige Abfrage

Beachten Sie die Bedingungen. Die Ergebnistabelle muß die Zeiträume zwischen dem ‚login‘ ausschließen und dem ersten anderen Ereignisse; ferner muss er die Zeit zwischen ‚Logout‘ und dem nächsten Ereignisse (vermutlich ein ‚login‘) auszuschließen. Die Selbstverknüpfung zwischen der Tabelle auf der namen Spalte und dann die asymmetrischen kommt auf der Zeit Spalte (mit ‚<‘) stellt sicher, dass die Ereignisse in zeitlicher Reihenfolge sind. Die NICHT VORHANDEN Unter wählen Sie sorgt dafür, dass nur benachbarte Ereignisse betrachtet werden. Unter Verwendung zwischen und in der Unterabfrage ist ein Fehler, weil es seine Endpunkte enthält, und es ist entscheidend, dass r1.time und r2.time sind aus dem Bereich ausgeschlossen; es dauerte ein paar Minuten, dass die Fehler zu erkennen (die Abfrage lief, kehrte aber keine Zeilen, aber Warum ?)!

SELECT r1.name, r1.state, r2.TIME - r1.TIME AS duration
    FROM eventtable r1, eventtable r2
    WHERE r1.name = r2.name
      AND r1.time < r2.time
      AND r1.state != 'login'
      AND r1.state != 'Logout'
      AND r1.time BETWEEN DATETIME(10:00) HOUR TO MINUTE
                      AND DATETIME(10:15) HOUR TO MINUTE
      AND r2.time BETWEEN DATETIME(10:00) HOUR TO MINUTE
                      AND DATETIME(10:15) HOUR TO MINUTE
      AND NOT EXISTS (SELECT 1 FROM eventtable r3
                            WHERE r3.time > r1.time AND r3.time < r2.time
                      AND r3.name = r1.name
                      AND r3.name = r2.name);

Dies erzeugt die Antwort:

name state      duration
a    chatting   0:02
a    Idle       0:02
b    chatting   0:01

c    chatting   0:01
c    Idle       0:01
c    Idle       0:01
c    Idle       0:01
c    chatting   0:01
c    Idle       0:01
c    chatting   0:01
c    Idle       0:01

Die ‚Dauer‘ Wert ist ein Intervall Stunde zu Minute; wenn Sie einen Wert in nur wenigen Minuten wollen, müssen Sie es mit einer Besetzung umwandeln (4 für die Präzision mit bis zu 1440 Minuten Intervallen zu ermöglichen, oder 1 Tag; die Daten für einen längeren Zeitrahmen nicht eindeutig ist):

(r2.time - r1.time)::INTERVAL MINUTE(4) TO MINUTE

Oder:

CAST (r2.time - r1.time AS INTERVAL MINUTE(4) TO MINUTE)

IBM Informix Dynamic Server (IDS) hat eine sehr ausführliche Notationen für Zeitkonstanten. 00: Im Standard-SQL, können Sie Zeit wie die Art und TIME '10 verwenden 00' als Wert, aber die Sekunden würden in strengem Standard-SQL erforderlich. IDS tut genau Arten liefern, die Menschen wollen - wie DATETIME- Stunde zu Minute. Sie würden auch INTERVAL MINUTE (4) in Standard-SQL schreiben; die 'MINUTE' sollte optional sein.

Falsche Abfrage

In meinem Kommentar zu Ray Hidayat Antwort, habe ich darauf hingewiesen, dass die EXISTS Unterabfrage notwendig ist, um sicherzustellen, dass die Ereignisse unter Berücksichtigung angrenzen - sind keine dazwischenliegenden Ereignisse. Hier ist die gleiche Abfrage mit Start- und Endzeiten an den Ausgang gegeben, und die EXISTS-Klausel fehlt (und ‚Dauer‘ umbenannt zu ‚Ablauf‘):

SELECT r1.name, r1.state, r2.TIME - r1.TIME AS lapse,
       r1.time AS start, r2.time AS end
    FROM eventtable r1, eventtable r2
    WHERE r1.name = r2.name
      AND r1.time < r2.time
      AND r1.state != 'login'
      AND r1.state != 'Logout'
      AND r1.time BETWEEN DATETIME(10:00) HOUR TO MINUTE
                      AND DATETIME(10:15) HOUR TO MINUTE
      AND r2.time BETWEEN DATETIME(10:00) HOUR TO MINUTE
                      AND DATETIME(10:15) HOUR TO MINUTE;

Dies erzeugt die Antwort:

name state     lapse start end
a    chatting   0:04 10:06 10:10
a    chatting   0:02 10:06 10:08
a    Idle       0:02 10:08 10:10
b    chatting   0:01 10:11 10:12
c    chatting   0:13 10:02 10:15
c    chatting   0:12 10:02 10:14
c    chatting   0:11 10:02 10:13
c    chatting   0:10 10:02 10:12
c    chatting   0:09 10:02 10:11
c    chatting   0:07 10:02 10:09
c    chatting   0:06 10:02 10:08
c    chatting   0:05 10:02 10:07
c    chatting   0:04 10:02 10:06
c    chatting   0:03 10:02 10:05
c    chatting   0:02 10:02 10:04
c    chatting   0:01 10:02 10:03
c    Idle       0:12 10:03 10:15
c    Idle       0:11 10:03 10:14
c    Idle       0:10 10:03 10:13
c    Idle       0:09 10:03 10:12
c    Idle       0:08 10:03 10:11
c    Idle       0:06 10:03 10:09
c    Idle       0:05 10:03 10:08
c    Idle       0:04 10:03 10:07
c    Idle       0:03 10:03 10:06
c    Idle       0:02 10:03 10:05
c    Idle       0:01 10:03 10:04
c    Idle       0:10 10:05 10:15
c    Idle       0:09 10:05 10:14
c    Idle       0:08 10:05 10:13
c    Idle       0:07 10:05 10:12
c    Idle       0:06 10:05 10:11
c    Idle       0:04 10:05 10:09
c    Idle       0:03 10:05 10:08
c    Idle       0:02 10:05 10:07
c    Idle       0:01 10:05 10:06
c    Idle       0:08 10:07 10:15
c    Idle       0:07 10:07 10:14
c    Idle       0:06 10:07 10:13
c    Idle       0:05 10:07 10:12
c    Idle       0:04 10:07 10:11
c    Idle       0:02 10:07 10:09
c    Idle       0:01 10:07 10:08
c    chatting   0:04 10:11 10:15
c    chatting   0:03 10:11 10:14
c    chatting   0:02 10:11 10:13
c    chatting   0:01 10:11 10:12
c    Idle       0:03 10:12 10:15
c    Idle       0:02 10:12 10:14
c    Idle       0:01 10:12 10:13
c    chatting   0:02 10:13 10:15
c    chatting   0:01 10:13 10:14
c    Idle       0:01 10:14 10:15

Dies zeigt, wie jede qualifizierte Startreihe für den Benutzer ‚c‘ mit jeder qualifizierten Ende Reihe angepasst ist, viele unechten Reihen von Daten zu geben. Die NICHT VORHANDEN Unter Abfrage ein gemeinsames Thema ist, wenn sie mit zeitbasierte Abfragen zu tun. Sie können Informationen über diese Vorgänge in Snodgrass des „ Entwicklung zeitorientierten Anwendungen in SQL finden "(PDF online verfügbar unter URL), und in Datum, Darwen und Lorentzos" Temporal Daten und das relationale Modell “.

Andere Tipps

Ich bin ziemlich sicher, es kann nur mit SQL getan werden, es geht mir ziemlich viel Zeit mit einer Abfrage für Sie zu kommen zu nehmen, ich es in bearbeiten werde, wenn ich fertig bin. Die grundlegenden Schritte, die ich denke, wären zuerst die Höhe der Zeit zu berechnen jeweils eine (erfolgt durch jeden Eintrag zu nehmen und es zum nächsten Eintrag Füge- und Subtrahieren die Zeitdifferenz zu finden) nimmt dann eine einfache Gruppe von Klausel mit einer Summe wird leicht bekommen es in die Form haben Sie beschrieben.

Edit: Hier ist, was ich kam mit

SELECT l.userid, l.state, SUM(t.minutes) AS duration
FROM Log l 
INNER JOIN (
    SELECT l1.id, (l2.time - l1.time) AS minutes
    FROM Log l1, Log l2
    WHERE l2.time == ( 
        -- find the next entry --
        SELECT TOP 1 ls.time
        FROM Log ls
        WHERE ls.Time > l1.Time && ls.userid = l1.userid
        ORDER BY ls.Time
    )
) t ON l.id == t.id
GROUP BY l.userid, l.state
ORDER BY l.userid

Dieses halb-Pseudo-Code ist, dass ich aus alle Tabellennamen und Dinge, und Sie werden von einem anderen nicht nur einmal in der Lage zu subtrahieren, werden Sie wahrscheinlich die DATEDIFF-Funktion verwenden. Abgesehen davon aber, glaube ich, dass der Kern von ihm ist. Ich denke, SQL eine der erstaunlichsten Sprachen ist, können Sie fast alles, was mit wenig Code.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top