bitte ich brauche Hilfe dabei (zum besseren Verständnis siehe angehängtes Bild), weil ich völlig hilflos bin.
Wie Sie sehen können, habe ich Benutzer und sie speichern ihre Anfangs- und Enddatum in meiner Datenbank als JJJJ-MM-TT H: i: s. Jetzt muss ich Überlappungen für alle Benutzer nach den häufigsten Überlappungen des Zeitbereichs herausfinden (für die meisten Benutzer). Ich möchte für die meisten Benutzer 3 häufigste Datenüberschneidungen erhalten. Wie kann ich es tun?
Ich habe keine Ahnung, welche MySQL-Abfrage ich verwenden soll, oder vielleicht wäre es besser, alle Datumsangaben (Anfang und Ende) aus der Datenbank auszuwählen und sie in PHP zu verarbeiten (aber wie?). Wie auf den Bildern angegeben, sollte zum Beispiel die Zeit 8.30 - 10.00 das Ergebnis für die Benutzer A + B + C + D sein.
%Vor%Was Sie effektiv haben, ist eine Sammlung von Sätzen und Sie möchten feststellen, ob einer von ihnen nicht-null-Schnittpunkte hat. Dies ist die genaue Frage, die man stellt, wenn man versucht, alle Vorfahren eines Knotens in einer verschachtelten Menge zu finden.
Wir können beweisen, dass für jede Überlappung mindestens ein Zeitfenster eine Startzeit hat, die in alle anderen überlappenden Zeitfenster fällt. Mit diesem Leckerbissen brauchen wir keine künstlichen Zeitschlitze am Tag zu konstruieren. Nehmen Sie einfach eine Startzeit und sehen Sie, ob sie eines der anderen Zeitfenster schneidet und dann nur die Anzahl der Kreuzungen zählt.
Also, was ist die Abfrage?
%Vor%Abhängig von Ihrer Tabellengröße und davon, wie oft Sie diese Abfrage ausführen möchten, kann es sinnvoll sein, einen räumlichen Index darauf zu setzen (siehe unten).
Wenn Sie diese Abfrage häufig ausführen, müssen Sie einen räumlichen Index verwenden. Wegen der bereichsbasierten Traversierung (dh liegt start_time zwischen dem Bereich von Start / Ende), wird ein BTREE-Index nichts für Sie tun. Es muss räumlich sein.
%Vor%Dann können Sie die ON-Klausel in der obigen Abfrage aktualisieren, um
zu lesen %Vor%Dadurch erhalten Sie eine indizierte Traversierung für die Abfrage. Tun Sie das erneut, wenn Sie die Abfrage häufig ausführen.
Kredit für den räumlichen Index zu Quassonis Blog .
Etwas wie das sollte dich beginnen -
%Vor%Die Idee besteht darin, eine abgeleitete Tabelle zu erstellen, die aus Zeitfenstern für den Tag besteht. In diesem Beispiel habe ich einen Dummy (der jede Tabelle mit einer AI-ID sein kann, die zusammenhängend für den erforderlichen Satz ist) verwendet, um eine Liste von Zeitschlitzen durch schrittweises Hinzufügen von 30 Minuten zu erstellen. Das Ergebnis wird dann zu Buchungen hinzugefügt, um die Anzahl der Bücher für jedes Zeitfenster zählen zu können.
UPDATE Für den gesamten Datums- / Zeitbereich können Sie eine Abfrage wie diese verwenden, um die anderen erforderlichen Daten zu erhalten -
%Vor%Diese Werte können dann in die ursprüngliche Abfrage eingefügt werden oder die beiden können kombiniert werden -
%Vor% BEARBEITEN Ich habe DISTINCT
und ORDER BY
Klauseln in GROUP_CONCAT()
als Antwort auf Ihre letzte Anfrage hinzugefügt.
Bitte beachten Sie, dass Sie in der Dummytabelle einen viel größeren Bereich von IDs benötigen. Ich habe diese Abfrage nicht getestet, so dass Syntaxfehler auftreten können.
Ich würde nicht viel in SQL machen, das ist so viel einfacher in einer Programmiersprache, SQL ist nicht für so etwas gemacht.
Natürlich ist es nur vernünftig, den Tag in "Timeslots" zu zerlegen - das sind Statistiken. Aber sobald Sie beginnen, Daten über den 00:00 Rand zu behandeln, werden die Dinge eklig, wenn Sie Joins und innere Selects verwenden. Vor allem bei MySQL, das interne Selects nicht ganz mag.
Hier ist eine mögliche SQL-Abfrage
%Vor%Hier ist ein Pseudocode
%Vor% Ja, das macht numslots
Abfragen, aber keine Joins, nichts, daher sollte es ziemlich schnell sein. Sie können auch die Auflösung leicht ändern.
Und noch eine positive Sache ist, du könntest dich "fragen", "Ich habe zwei mögliche Zeitfenster, und ich brauche das, wo mehr Leute hier sind, welches soll ich benutzen?" und führen Sie die Abfrage einfach zweimal mit den entsprechenden Bereichen aus und Sie sind nicht mit vordefinierten Zeitfenstern festgefahren.
Um nur vollständige Überlappungen zu finden (ein Eintrag zählt nur, wenn er den gesamten Slot abdeckt), müssen Sie in der Abfrage den unteren und oberen Bereich wechseln.
Sie haben vielleicht bemerkt, dass ich keine Zeiten zwischen Einträgen addiere, die sich über mehrere Tage erstrecken könnten. Wenn Sie jedoch einen ganzen Tag hinzufügen, werden alle Slots um eins erhöht, was das ziemlich nutzlos macht.
Sie könnten sie jedoch hinzufügen, indem Sie sum(DAY(End) - DAY(Start))
auswählen und den Rückgabewert einfach zu allen Slots hinzufügen.
Tabelle scheint ziemlich einfach zu sein. Ich würde Ihre SQL-Abfrage ziemlich einfach halten:
SELECT * FROM Tabellenname
Wenn Sie die Informationen in Ihrem PHP-Objekt gespeichert haben. Mach die Verarbeitung mit PHP mit Schleifen und Vergleichen.
In der einfachsten Form:
%Vor%Natürlich ist das in sehr einfacher Form. Wahrscheinlich möchten Sie eine Schleife durch das Array machen, um zuerst alle Benutzer-IDs zu erhalten, bevor Sie sie in der oben gezeigten Schleife vergleichen.