2016-12-15 6 views
1

Stackoverflow,Wählen Sie erste und letzte Übereinstimmung nach Spalte aus einer Zeitstempel-Tabelle in MySQL

Ich brauche deine Hilfe!

sagen, dass ich eine Tabelle in MySQL haben, die etwa wie folgt aussieht:

------------------------------------------------- 
OWNER_ID | ENTRY_ID | VEHICLE | TIME | LOCATION 
------------------------------------------------- 
1|1|123456|2016-01-01 00:00:00|A 
1|2|123456|2016-01-01 00:01:00|B 
1|3|123456|2016-01-01 00:02:00|C 
1|4|123456|2016-01-01 00:03:00|C 
1|5|123456|2016-01-01 00:04:00|B 
1|6|123456|2016-01-01 00:05:00|A 
1|7|123456|2016-01-01 00:06:00|A 
... 
1|999|123456|2016-01-01 09:10:00|A 
1|1000|123456|2016-01-01 09:11:00|A 
1|1001|123456|2016-01-01 09:12:00|B 
1|1002|123456|2016-01-01 09:13:00|C 
1|1003|123456|2016-01-01 09:14:00|C 
1|1004|123456|2016-01-01 09:15:00|B 
... 

Bitte beachten Sie, dass das Tabellenschema besteht aus nur so kann ich erklären, was ich zu tun habe versucht .. .

Stellen Sie sich vor, dass von ENTRY_ID 6 bis 999 die Spalte LOCATION "A" ist. Alles, was ich für meine Anwendung brauche, ist im Grunde die Zeilen 1-6, dann die Zeile 1000 weiter. Alles von Zeile 7 bis 999 sind unnötige Daten, die nicht weiter verarbeitet werden müssen. Ich bemühe mich, diese Zeilen entweder zu ignorieren, ohne die Verarbeitung der Daten in meine Anwendung verschieben zu müssen, oder besser noch, sie zu löschen.

ich kratzen meinen Kopf mit diesem, weil:

1) I von LOCATION nicht sortieren kann dann nur die ersten und letzten Einträge, weil die Zeit, um meine Bewerbung wichtig ist, und dies wird verloren gehen - Wenn ich diese Daten beispielsweise auf diese Weise verarbeite, würde ich Zeile 1 und Zeile 1000 verlieren und Zeile 6 verlieren.

2) Ich würde es vorziehen, die Verarbeitung dieser Daten nicht in meine Anwendung zu verschieben, Diese Daten sind für meine Anforderungen überflüssig und es ist einfach sinnlos, sie zu behalten, wenn ich sie vermeiden kann.

In Anbetracht der obigen Beispiel Daten, was ich mit am Ende wollen, sobald ich eine Lösung haben wäre:

------------------------------------------------- 
OWNER_ID | ENTRY_ID | VEHICLE | TIME | LOCATION 
------------------------------------------------- 
1|1|123456|2016-01-01 00:00:00|A 
1|2|123456|2016-01-01 00:01:00|B 
1|3|123456|2016-01-01 00:02:00|C 
1|4|123456|2016-01-01 00:03:00|C 
1|5|123456|2016-01-01 00:04:00|B 
1|6|123456|2016-01-01 00:05:00|A 
1|1000|123456|2016-01-01 09:11:00|A 
1|1001|123456|2016-01-01 09:12:00|B 
1|1002|123456|2016-01-01 09:13:00|C 
1|1003|123456|2016-01-01 09:14:00|C 
1|1004|123456|2016-01-01 09:15:00|B 
... 

Hoffentlich Sinn mache ich hier und nicht etwas offensichtlich fehlt!

@Aliester - Gibt es eine Möglichkeit, um festzustellen, dass eine Zeile nicht zu von den in dieser Zeile enthaltenen Daten verarbeitet benötigt?

Leider nicht.

@O. Jones - Es scheint, als ob Sie hoffen, den frühesten und neuesten Zeitstempel in Ihrer Tabelle für jeden einzelnen Wert von ENTRY_ID, zu ermitteln und dann die Detailzeilen aus der Tabelle mit diesen Zeitstempeln abzurufen. Ist das korrekt? Sind Ihre ENTRY_ID-Werte eindeutig? Sind sie garantiert in aufsteigender Reihenfolge? Ihre Abfrage kann billiger gemacht werden, wenn das wahr ist. Bitte, wenn Sie Zeit haben, bearbeiten Sie Ihre Frage , um diese Punkte zu klären.

Ich versuche die Ankunftszeit an einem Ort zu finden, gefolgt von der Abfahrtszeit von diesem Ort. Ja, ENTRY_ID ist ein eindeutiges Feld, aber Sie können nicht davon ausgehen, dass eine frühere ENTRY_ID einem früheren Zeitstempel entspricht - die eingehenden Daten werden von einer GPS-Einheit eines Fahrzeugs gesendet und NICHT unbedingt in der Reihenfolge verarbeitet, in der sie gesendet werden Netzwerkeinschränkungen.

+0

Gibt es eine Möglichkeit zu bestimmen, dass eine Zeile aus den Daten in dieser Zeile nicht verarbeitet werden muss? – Adrian

+0

Es klingt, als ob Sie hoffen, den frühesten und spätesten Zeitstempel in Ihrer Tabelle für jeden einzelnen Wert von 'ENTRY_ID' zu ermitteln und dann die Detailzeilen aus der Tabelle abzurufen, die diesen Zeitstempeln entsprechen. Ist das korrekt? Sind Ihre 'ENTRY_ID' Werte einzigartig? Sind sie garantiert in aufsteigender Reihenfolge? Ihre Anfrage kann billiger gemacht werden, wenn das stimmt. Bitte, wenn Sie Zeit haben, [bearbeiten] Sie Ihre Frage, um diese Punkte zu klären. –

+0

Zur weiteren Erläuterung. Was macht in Ihrem ersten Beispiel die Zeilen 1 und 6 für das Dataset relevant, das Sie behalten möchten, und was macht Zeile 7 für dieses Dataset irrelevant? –

Antwort

1

Dies ist ein schwieriges Problem in SQL zu lösen, da es sich bei SQL um Datensätze handelt, nicht um Datensequenzen.Es ist besonders schwierig in MySQL, weil andere SQL-Varianten eine synthetische ROWNUM-Funktion haben und MySQL nicht ab Ende 2016.

Sie benötigen die Vereinigung von zwei Datensätzen hier.

  1. die Reihe von Zeilen Ihrer Datenbank unmittelbar vor, in der Zeit, eine Änderung des Standorts.
  2. der Satz von Zeilen unmittelbar nach einer Standortänderung.

Um das zu bekommen, müssen Sie mit einer Unterabfrage starten, die alle Ihre Zeilen erzeugt, geordnet nach VEHICLE dann TIME, mit Zeilennummern. (http://sqlfiddle.com/#!9/6c3bc7/2/0) Bitte beachten Sie, dass sich die Beispieldaten in Sql Fiddle von Ihren Beispieldaten unterscheiden.

 SELECT (@rowa := @rowa + 1) rownum, 
       loc.* 
      FROM loc 
      JOIN (SELECT @rowa := 0) init 
     ORDER BY VEHICLE, TIME 

Dann müssen Sie sich selbst zu verbinden, dass die Unterabfrage, verwenden Sie die ON-Klausel aufeinander folgende Zeilen an der gleichen Stelle auszuschließen, und nehmen Sie die Zeilen direkt vor einer Änderung der Lage. Der Vergleich aufeinanderfolgender Zeilen erfolgt über ON ... b.rownum = a.rownum+1. Das ist diese Abfrage. (http://sqlfiddle.com/#!9/6c3bc7/1/0)

SELECT a.* 
FROM (
      SELECT (@rowa := @rowa + 1) rownum, 
        loc.* 
       FROM loc 
       JOIN (SELECT @rowa := 0) init 
      ORDER BY VEHICLE, TIME 
) a 
JOIN (
      SELECT (@rowb := @rowb + 1) rownum, 
        loc.* 
       FROM loc 
       JOIN (SELECT @rowb := 0) init 
      ORDER BY VEHICLE, TIME 
) b ON a.VEHICLE = b.VEHICLE 
     AND b.rownum = a.rownum + 1 
     AND a.location <> b.location 

Eine Variante dieser Unterabfrage, in der Sie SELECT b.* sagen, bekommt die Zeilen direkt nach einer Änderung der Lage (http://sqlfiddle.com/#!9/6c3bc7/3/0)

Schließlich nehmen Sie die setwise UNION dieser beiden Abfragen, um Es ist angemessen, und Sie haben Ihre Reihe von Zeilen mit den doppelten aufeinanderfolgenden Positionen entfernt. Bitte beachten Sie, dass dies in MySQL recht ausführlich wird, da der böse Hack, der zum Generieren von Zeilennummern verwendet wird, eine andere Variable (@rowa, @rowb, usw.) in jeder Kopie der Unterabfrage verwenden muss. (http://sqlfiddle.com/#!9/6c3bc7/4/0)

SELECT a.* 
    FROM (
     SELECT (@rowa := @rowa + 1) rownum, 
       loc.* 
      FROM loc 
      JOIN (SELECT @rowa := 0) init 
     ORDER BY VEHICLE, TIME 
) a 
JOIN (
     SELECT (@rowb := @rowb + 1) rownum, 
       loc.* 
      FROM loc 
      JOIN (SELECT @rowb := 0) init 
     ORDER BY VEHICLE, TIME 
) b ON a.VEHICLE = b.VEHICLE AND b.rownum = a.rownum + 1 AND a.location <> b.location 

UNION 

SELECT d.* 
    FROM (
     SELECT (@rowc := @rowc + 1) rownum, 
       loc.* 
      FROM loc 
      JOIN (SELECT @rowc := 0) init 
     ORDER BY VEHICLE, TIME 
) c 
JOIN (
     SELECT (@rowd := @rowd + 1) rownum, 
       loc.* 
      FROM loc 
      JOIN (SELECT @rowd := 0) init 
     ORDER BY VEHICLE, TIME 
) d ON c.VEHICLE = d.VEHICLE AND c.rownum = d.rownum - 1 AND c.location <> d.location 
order by VEHICLE, TIME 

Und in der nächsten Generation von MySQL, erhältlich in der Beta jetzt in MariaDB 10.2, das ist viel viel einfacher. Die neue Generation als allgemeine Tabellenausdrücke und Zeilennummerierung.

with loc as 
    (
      SELECT ROW_NUMBER() OVER (PARTITION BY VEHICLE ORDER BY time) rownum, 
        loc.* 
       FROM loc 
) 

select a.* 
from loc a 
join loc b ON a.VEHICLE = b.VEHICLE 
      AND b.rownum = a.rownum + 1 
      AND a.location <> b.location 
union 
select b.* 
from loc a 
join loc b ON a.VEHICLE = b.VEHICLE 
      AND b.rownum = a.rownum + 1 
      AND a.location <> b.location 
order by vehicle, time 
Verwandte Themen