Re: Abfrage bei Sybase SQL Anywhere 9
- From: Florian Weimer <fw@xxxxxxxxxxxxx>
- Date: Sun, 09 Mar 2008 08:02:34 +0100
* Andreas Bihler:
Angenommen wir haben folgende Einträge:
0123, Test1, 2, 31.10.2006
4567, Test2, 1, 10.01.2008
0123, Test1, 2, 11.02.2008
Nun gebe ich als Zeitgrenze den 01.02.2008 an.
Als Ergebnis müsste dann folgendes kommen:
4567, Test2, 1, 10.01.2008
Ist das der Eintrag für den letzten Verkauf? Das ist mit Standard-SQL
eher schwierig umzusetzen, fürchte ich, gerade wenn die Tabelle keinen
Primärschlüssel hat. Wenn Sybase so etwas wie DISTINCT ON kann, dann
geht es aber. Die infragekommenden Artikelnummern bekommst Du jedenfalls
mit:
SELECT ArtikelNr FROM Tabelle
EXCEPT SELECT ArtikelNr FROM Tabelle WHERE Datum > '2008-02-01'
Jetzt mußt Du noch den Kompletten Datensatz dazu finden. Mit DISTINCT ON
ist es relativ einfach:
SELECT DISTINCT ON (ArtikelNr) *
WHERE ArtikelNr IN (SELECT von oben)
ORDER BY Datum DESC
Das hat den Vorteil, daß man die Tabellenspalten nicht explizit
aufführen muß, so daß diese Abfrage recht wartungsarm ist.
Ohne DISTINCT ON ist es eher schwierig. Wir müssen erst einmal einen
Primärschlüssel in der passenden Sortierung erzeugen:
SELECT COUNT(*) AS pk, t1.* FROM Tabelle t1, Tabelle t2
WHERE (t1.Datum, t1.ArtikelNr, t1.ArtikelName, t1.Anzahl)
>= (t2.Datum, t2.ArtikelNr, t2.ArtikelName, t2.Anzahl)
Es kann sein, daß Transact-SQL keine Tupel-Vergleiche unterstützt, dann
muß man das eben manuell hinschreiben:
t1.Datum > t2.Datum
OR (t1.Datum = t2.Datum AND t1.ArtikelNr > t2.ArtikelNr)
OR (t1.Datum = t2.Datum AND t1.ArtikelNr = t2.ArtikelNr AND ...)
...
Am besten erzeugt man soetwas mit einem kleinen Skript (wie auch den
folgenden Sermon).
Mit ROWNUM, generate_series o.ä. kann man den Self-Join mit seinem
quadratischen Laufzeitverhalten loswerden, zum Beispiel:
SELECT ROWNUM AS pk, * FROM Tabelle ORDER BY Datum
Oder, was neueres Sybase eher unterstützt:
SELECT RANK() OVER (ORDER BY Datum) AS pk, * FROM Tabelle
(Der Self-Join-Trick hat auch Probleme mit Duplikaten, was aber im
folgenden keine Rolle spielen sollte.)
Wenn man das gebastelt hat, kann man zu jedem Artikel einen beliebigen
letzten Kaufvorgang zu ermitteln:
WITH TabellePK (pk, ArtikelNr, ArtikelName, Anzahl, Datum) AS (
SELECT RANK() OVER (ORDER BY Datum) AS pk, * FROM Tabelle
)
SELECT ArtikelNr, MAX(pk) FROM TabellePK GROUP BY ArtikelNr
(Keine Ahnung ob die Syntax en detail korrekt ist, ich kenne WITH nur
aus der Dokumentation, da PostgreSQL das nicht unterstützt. Das WITH ist
aber hier und im folgenden nicht essentiell, man kann das über eine
temporäre Tabelle emulieren oder über manuelles Expandieren des
SELECTs.)
Wenn wir das mit der anfänglichen Abfrage verheiraten, kommt folgendes
heraus:
WITH TabellePK (pk, ArtikelNr, ArtikelName, Anzahl, Datum) AS (
SELECT RANK() OVER (ORDER BY Datum) AS pk, * FROM Tabelle
)
SELECT t1.ArtikelNr, t1.ArtikelName, t1.Anzahl, t1.Datum
FROM TabellePK t1,
(SELECT ArtikelNr, MAX(pk) FROM TabellePK GROUP BY ArtikelNr) t2
WHERE t1.pk = t2.pk
AND t2.ArtikelNr IN (SELECT ArtikelNr FROM Tabelle
EXCEPT SELECT ArtikelNr
FROM Tabelle WHERE Datum > '2008-02-01')
Oder auch:
WITH TabellePK (pk, ArtikelNr, ArtikelName, Anzahl, Datum) AS (
SELECT RANK() OVER (ORDER BY Datum) AS pk, * FROM
(SELECT * FROM Tabelle
EXCEPT SELECT * FROM Tabelle WHERE Datum > '2008-02-01') t
)
SELECT t1.ArtikelNr, t1.ArtikelName, t1.Anzahl, t1.Datum
FROM TabellePK t1,
(SELECT ArtikelNr, MAX(pk) FROM TabellePK GROUP BY ArtikelNr) t2
WHERE t1.pk = t2.pk
Das sollte, was die Effizienz der Ausführung angeht, mit dem
DISTINCT-ON-Ansatz vergleichbar sein, da der teure Teil das EXCEPT ist.
Wenn Dein Sybase noch kein RANK() hast, wird es aber ziemlich übel.
(Alles natürlich mangels Sybase ungetest. 8-)
.
- Follow-Ups:
- Re: Abfrage bei Sybase SQL Anywhere 9
- From: Dieter Noeth
- Re: Abfrage bei Sybase SQL Anywhere 9
- References:
- Abfrage bei Sybase SQL Anywhere 9
- From: Andreas Bihler
- Abfrage bei Sybase SQL Anywhere 9
- Prev by Date: Re: Abfrage bei Sybase SQL Anywhere 9
- Next by Date: Re: Abfrage bei Sybase SQL Anywhere 9
- Previous by thread: Re: Abfrage bei Sybase SQL Anywhere 9
- Next by thread: Re: Abfrage bei Sybase SQL Anywhere 9
- Index(es):
Relevant Pages
|