Delphi-PRAXiS
Seite 1 von 3  1 23      

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Programmieren allgemein (https://www.delphipraxis.net/40-programmieren-allgemein/)
-   -   SQL: benachbarte Datensätze mitselektieren (https://www.delphipraxis.net/136607-sql-benachbarte-datensaetze-mitselektieren.html)

Hedge 3. Jul 2009 20:32


SQL: benachbarte Datensätze mitselektieren
 
Folgendes Problem.
Meine Datensätze werden geordnet.
Für einen bestimmten Datensatz ist der Primary-Key bekannt.

Aus der Tabelle möchte ich dieses Element inklusive der 2 nächstkleineren Elemente und der 2 nächstgrößeren Elemente als Ergebnismenge verarbeiten.

Hat Jemand eine Idee wie ich das mit weniger als 3 Queries schaffen kann?

alcaeus 3. Jul 2009 20:42

Re: SQL: Nachbarn eines Datensatzes mitselektien
 
Moin,

es ist eigentlich simpel: nehmen wir an, du sortierst nach dem Feld id. Dir ist die ID des eigentlichen Datensatzes bekannt, d.h. du selektierst erstmal das Objekt:
SQL-Code:
SELECT * FROM foo WHERE id = %id
Anschliessend selektierst du die naechsten 2 Datensaetze:
SQL-Code:
SELECT * FROM foo WHERE id > %id ORDER BY id ASC LIMIT 2
Und zu guter Letzt noch die vorherigen beiden:
SQL-Code:
SELECT * FROM foo WHERE id < %id ORDER BY id DESC LIMIT 2
So, das waren jetzt drei. Wir koennen die ersten beiden Queries aber verbinden:
SQL-Code:
SELECT * FROM foo WHERE id >= %id ORDER BY id ASC LIMIT 3
Nun weisst du dass die erste Row des Ergebnis-Sets der eigentliche Datensatz ist und alles was nachher kommt sind die naechsten Datensaetze, und hast das Ganze in 2 Queries. Auf ein Query runterzukommen geht eigentlich nur mit Hilfe von UNION:
SQL-Code:
(SELECT * FROM foo WHERE id < %id ORDER BY id DESC LIMIT 2)
UNION (SELECT * FROM foo WHERE id >= %id ORDER BY id ASC LIMIT 3)
ORDER BY id ASC
Hab ich grad nicht getestet, muesste aber funktionieren. Das Ding ist allerdings ein Trugschluss, da der DB-Server intern sowieso 2 Queries ausfuehrt, von daher kannst du es uebersichtlicher halten, wenn du getrennt selektierst.

Lustiger wird das Ganze wenn du nicht ein Sortierkriterium hast, sondern mehrere. Nehmen wir an du hast einen Vornamen (firstname) und einen Nachnamen (lastname) und moechtest nach der Form lastname, firstname sortieren und selektieren. In dem Fall musst du die Sortierung selbst basteln:

SQL-Code:
SELECT * FROM foo WHERE lastname > %lastname OR (lastname = %lastname AND firstname > %firstname) ORDER BY lastname ASC, firstname ASC LIMIT 2
SQL-Code:
SELECT * FROM foo WHERE lastname < %lastname OR (lastname = %lastname AND firstname < %firstname) ORDER BY lastname DESC, firstname DESC LIMIT 2
Du kannst dir vorstellen, wie sich das Ding aufblaeht, wenn du dann 5 Kriterien drin hast ;)
In diesem Fall ist es uebrigens fast immer geschickter, mit 3 Queries zu arbeiten. Schliesslich wird dein Datensatz wohl kaum per Vor- und Nachname definiert werden, sondern per ID. Also musst du dir erstmal die Grenzen aus der Datenbank holen, was in diesem Fall nicht mit einem Subquery oder JOIN gemacht werden sollte, da du ihn gleich zwei Mal machen musst (einmal fuer die vorherigen 2 Datensaetze, einmal fuer die nachfolgenden). Dein DB-Server wirds dir spaetestens ab 4-stelligen Datensatzzahlen danken *g*

Greetz
alcaeus

Hedge 3. Jul 2009 20:46

Re: SQL: benachbarte Datensätze mitselektieren
 
Wow super.
Immerhin nur 2 Abfragen :)

Könnte man das Ganze mit Stored Procedures verbessern?

EDIT: Mein Fall ist noch ein wenig schwieriger.
Mir ist die ID des Users geläufig nach der ich selektieren kann, aber nicht wie groß das Sortierkriterium des Users ist.
Also sind es dann doch 3 Abfragen :/

alcaeus 3. Jul 2009 21:02

Re: SQL: benachbarte Datensätze mitselektieren
 
Zitat:

Zitat von Hedge
Mir ist die ID des Users geläufig nach der ich selektieren kann, aber nicht wie groß das Sortierkriterium des Users ist.

Du meinst also den letzten Fall, den ich beschrieben hab? Ja, in dem Fall musst du es leider mit dreien machen, es sei denn du willst mit Subqueries arbeiten:

SQL-Code:
SELECT * FROM foo a
WHERE a.sort >= (SELECT sort FROM foo b WHERE id = %id)
ORDER BY sort ASC
LIMIT 3
Das ist aber wieder nur Augenauswischerei, denn der DB-Server wird definitiv drei Queries machen. Du koenntest es ueber nen JOIN loesen, aber dann wirds ab ner gewissen Datensatzmenge einfach haesslich.

Greetz
alcaeus

Edith sagt: SPs? Keine Ahnung...als eingefleischter MySQL-User komm ich erst seit Kurzem in den Genuss solcher Features und hatte noch nicht die Zeit, mich damit zu befassen :oops:

Hansa 3. Jul 2009 21:18

Re: SQL: benachbarte Datensätze mitselektieren
 
SQL-Code:
for select first 3 M.ID, M.ABDATUM, M.MWSTWERT from MWST8 M
    where M.MWSTSATZ = :MWSTSATZ_OUT and M.ABDATUM <= :ABDATUM
    order by M.ABDATUM desc
    INTO :ID_OUT,:ABDATUM_OUT,:MWSTWERT_OUT DO
      SUSPEND;
    END
END
^
So ungefähr geht das mit SP unter Firebird. DB wurde nicht angegeben. First heißt woanders eventuell auch Limit oder sonstwie.

Hedge 3. Jul 2009 22:56

Re: SQL: benachbarte Datensätze mitselektieren
 
Ah danke.
Ich versuche es immer noch auf dem klassischen Weg.
Mir ist ne Idee gekommen.

Ist es möglich ein temporäres Feld einzuführen bei dem die Datensätze laufend nummeriert werden in der reihenfolge in der ich sie bei der 1. Abfrage sortiere?

Da könnte ich feststellen an welcher Position sich mein gesuchter datensatz mit Nummern ausgedrückt befindet und danach in einer Unterabfrage den Wertebereich einschränken.

omata 3. Jul 2009 23:03

Re: SQL: benachbarte Datensätze mitselektieren
 
Verrate uns doch erstmal welches DBMS du benutzt.

Hedge 3. Jul 2009 23:04

Re: SQL: benachbarte Datensätze mitselektieren
 
MySQL :)

omata 3. Jul 2009 23:08

Re: SQL: benachbarte Datensätze mitselektieren
 
Es gibt in einer Datenbank keine Reihenfolge, es sei denn man definiert eine. Kannst du mal deine Abfrage beispielhaft zeigen? Wie sieht dein Sortierkriterium aus?

Hedge 3. Jul 2009 23:11

Re: SQL: benachbarte Datensätze mitselektieren
 
SQL-Code:
SELECT score
FROM 'user'
WHERE 'user_id'= 1
Da kriegen wir den score her, den der jeweilige User hat

Nun sollen die Daten für diesen User und die 2 nächsten die mehr punkte haben und die 2 die weniger als er haben bestimmt werden

SQL-Code:
SELECT username,score,land
FROM `user`
WHERE ?!?!?!?
ORDER BY score DESC
LIMIT 5;


Alle Zeitangaben in WEZ +1. Es ist jetzt 16:13 Uhr.
Seite 1 von 3  1 23      

Powered by vBulletin® Copyright ©2000 - 2024, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024 by Thomas Breitkreuz