n'abend,
echo $begrüßung;
ich habe eine Datenbankabfrage in MYSQL die mir Datensätze nach Datum sortiert liefert.
Nun möchte ich in einem nummerischen Feld die Differenz zum jeweiligen nächsten Datensatz berechnen.
Gibt es auch eine Möglichkeit dies direkt in der SQL-Abfrage durchzuführen?Nein, das dürfte nicht gehen.
Es ist - wie so oft - nur eine Frage der Widerlichkeit.
Mittels Joins / Subselects lässt sich für jeden Datensatz der in der Sequenz nächste Datensatz "anbinden" - und somit auch eine Differenz ermitteln.
/* bauen wir uns eine simple Tabelle */
create table sequenz(
prike int(10) NOT NULL PRIMARY KEY auto_increment,
datum DATE
);
/* werfen wir ein bisschen Datenmüll rein */
INSERT INTO sequenz (datum) VALUES
('2008-09-19'),
('2008-09-09'),
('2008-08-30'),
('2008-08-08'),
('2008-08-08');
Auf unseren Demodaten können wir nun ein paar Abfragen fahren:
/* (Query01:) Folgedatensatz anhand des Feldes prike ermitteln, wobei immer der nächst höhere Wert angehängt werden soll. Lücken in der Sequenz sollen dabei keine Probleme machen */
SELECT *
FROM sequenz s1
JOIN sequenz s2
ON ( s2.prike = (
SELECT MIN(prike)
FROM sequenz si
WHERE si.prike > s1.prike )
);
+-------+------------+-------+------------+
| prike | datum | prike | datum |
+-------+------------+-------+------------+
| 1 | 2008-09-19 | 2 | 2008-09-09 |
| 2 | 2008-09-09 | 3 | 2008-08-30 |
| 3 | 2008-08-30 | 4 | 2008-08-08 |
| 4 | 2008-08-08 | 5 | 2008-08-08 |
+-------+------------+-------+------------+
/* (Query02:) Die Anforderungen von Query01 erweitert um die Differenz der Datümser™ */
SELECT *, DATEDIFF(s1.datum, s2.datum)
FROM sequenz s1
JOIN sequenz s2
ON ( s2.prike = (
SELECT MIN(prike)
FROM sequenz si
WHERE si.prike > s1.prike )
);
+-------+------------+-------+------------+------------------------------+
| prike | datum | prike | datum | DATEDIFF(s1.datum, s2.datum) |
+-------+------------+-------+------------+------------------------------+
| 1 | 2008-09-19 | 2 | 2008-09-09 | 10 |
| 2 | 2008-09-09 | 3 | 2008-08-30 | 10 |
| 3 | 2008-08-30 | 4 | 2008-08-08 | 22 |
| 4 | 2008-08-08 | 5 | 2008-08-08 | 0 |
+-------+------------+-------+------------+------------------------------+
Wir haben an dieser Stelle nun die Anzahl der Tage, die zwischen den Datümsern™ zwischen den Datensätzen liegen, welche anhand des Feldes prike verbunden wurden.
Freilich können wir den jeweils nächsten Datensatz auch anhand des Datums ermitteln
/* (Query03:) Die Anforderungen von Query02 mit datum als relevantes Feld zur Verbindung mit dem nächsten Datensatz: */
SELECT *, DATEDIFF(s1.datum, s2.datum)
FROM sequenz s1
JOIN sequenz s2 ON ( s2.datum = (
SELECT MIN(datum)
FROM sequenz si
WHERE si.datum > s1.datum ));
+-------+------------+-------+------------+------------------------------+
| prike | datum | prike | datum | DATEDIFF(s1.datum, s2.datum) |
+-------+------------+-------+------------+------------------------------+
| 2 | 2008-09-09 | 1 | 2008-09-19 | -10 |
| 3 | 2008-08-30 | 2 | 2008-09-09 | -10 |
| 4 | 2008-08-08 | 3 | 2008-08-30 | -22 |
| 5 | 2008-08-08 | 3 | 2008-08-30 | -22 |
+-------+------------+-------+------------+------------------------------+
Wie wir erkennen können gibt es hier zwei "Probleme". Zum einen sind die Differenzen negativ, zum anderen zeigen die beiden Datensätze 4 und 5 auf den Datensatz 3. Das erste Problem bekommen wir mit ABS() (Absolutwert) in den Griff. Um das ganze besser zu illustrieren fügen wir nochmal ein bisschen Datenmüll ein: INSERT INTO sequenz (datum) VALUES ('2008-09-19'), ('2008-09-29');
Gegen das zweite Problem können wir ohne den Einsatz einer weiteren verknüpfungsrelevanten Spalte nicht lösen.
/* (Query04:) Die Anforderungen von Query03 mit datum als relevantes Feld zur Verbindung mit dem nächsten Datensatz: */
SELECT *, ABS(DATEDIFF(s1.datum, s2.datum))
FROM sequenz s1
JOIN sequenz s2 ON ( s2.datum = (
SELECT MIN(datum)
FROM sequenz si
WHERE si.datum > s1.datum ));
+-------+------------+-------+------------+-----------------------------------+
| prike | datum | prike | datum | ABS(DATEDIFF(s1.datum, s2.datum)) |
+-------+------------+-------+------------+-----------------------------------+
| 2 | 2008-09-09 | 1 | 2008-09-19 | 10 |
| 3 | 2008-08-30 | 2 | 2008-09-09 | 10 |
| 4 | 2008-08-08 | 3 | 2008-08-30 | 22 |
| 5 | 2008-08-08 | 3 | 2008-08-30 | 22 |
| 2 | 2008-09-09 | 6 | 2008-09-19 | 10 |
| 1 | 2008-09-19 | 7 | 2008-09-29 | 10 |
| 6 | 2008-09-19 | 7 | 2008-09-29 | 10 |
+-------+------------+-------+------------+-----------------------------------+
Die Spielchen könnten noch beliebig weiter getrieben werden, aber hier ruft ein Bett nach mir... :)
weiterhin schönen abend...
#selfhtml hat ein Forum?
sh:( fo:# ch:# rl:| br:> n4:& ie:{ mo:} va:) de:] zu:} fl:( ss:? ls:[ js:|