2012-05-22 11 views
5

sagen dass ich habe einige SELECT Aussage:Suche Zeilennummer in einer Art auf Zeilen-ID basiert, dann seine Nachbarn

SELECT id, name FROM people 
    ORDER BY name ASC; 

Ich habe ein paar Millionen Zeilen in der people Tabelle und die ORDER BY Klausel kann viel sein komplexer als das, was ich hier gezeigt habe (möglicherweise auf einem Dutzend Spalten).

Ich erhalte nur eine kleine Teilmenge der Zeilen (sagen Zeilen 1..11), um sie in der Benutzeroberfläche anzuzeigen. Jetzt möchte ich folgende Probleme lösen:

  1. Finden Sie die Nummer einer Zeile mit einem gegebenen id.
  2. Zeigen Sie die 5 Artikel vor und die 5 Artikel nach einer Zeile mit einem gegebenen id an.

Problem 2 ist leicht zu lösen, wenn ich das Problem 1 gelöst habe, als ich dann so etwas wie diese verwenden kann, wenn ich weiß, dass der Artikel, den ich suchte Zeilennummer 1000 im sortierten Ergebnismenge hat (dies ist die Firebird SQL-Dialekt):

SELECT id, name FROM people 
    ORDER BY name ASC 
    ROWS 995 TO 1005; 

ich weiß auch, dass ich die rank einer Reihe von alle Zeilen zu zählen, die vor dem man kommen finden die ich suche, aber dies zu sehr langen WHERE Klauseln führen kann Tonnen von OR und AND in dem Zustand. Und ich muss das wiederholt tun. Bei meinen Testdaten dauert dies Hunderte von Millisekunden, selbst wenn richtig indizierte Spalten verwendet werden, was viel zu langsam ist.

Gibt es eine Möglichkeit, dies zu erreichen, indem Sie einige Funktionen von SQL: 2003 verwenden (wie row_number in Firebird 3.0 unterstützt)? Ich bin auf keinen Fall ein SQL-Guru und ich brauche hier ein paar Hinweise. Könnte ich eine zwischengespeicherte Ansicht erstellen, in der das Ergebnis einen rank/dichten Rang/Zeilenindex enthalten würde?

+0

zu schwer zu beantworten ohne Info über UI-Typ. Netz? Desktop? Befehlszeile? Voice UI ;-) – rstrelba

+0

Ich zeige eine Liste von Personen in einer Desktop-Anwendung; Da die Sammlung riesig ist, hole ich nur die Zeilen für die Personen, die in das Ansichtsfenster der Liste passen. Der Benutzer hat eine Bildlaufleiste, die es ihr erlaubt, sich an einen beliebigen Punkt in der Liste zu bewegen und ihren Inhalt so zu aktualisieren, als wäre er wirklich mit Millionen von Zeilen gefüllt. –

+0

Wie viele zusätzliche Parameter im Filter des Ansichtsfensters? – rstrelba

Antwort

3

Firebird scheint Fensterfunktionen zu unterstützen (in Oracle als analytische Funktionen bezeichnet). So können Sie Folgendes ausführen können:

Um die „Reihe“ Nummer eines einer Reihe mit einer bestimmten ID zu finden:

select id, row_number() over (partition by NULL order by name, id) 
from t 
where id = <id> 

Dies setzt voraus, einzigartig sind die IDs.

das zweite Problem lösen:

select t.* 
from (select id, row_number() over (partition by NULL order by name, id) as rownum 
     from t 
    ) t join 
    (select id, row_number() over (partition by NULL order by name, id) as rownum 
     from t 
     where id = <id> 
    ) tid 
    on t.rownum between tid.rownum - 5 and tid.rownum + 5 

ich etwas anderes vermuten lassen könnte, aber, wenn Sie die Tabellenstruktur ändern können. Die meisten Datenbanken bieten die Möglichkeit, beim Einfügen einer Zeile eine Spalte mit automatischer Erhöhung hinzuzufügen. Wenn Ihre Datensätze nie gelöscht werden, kann dies Server als Ihr Zähler verwenden und Ihre Abfragen vereinfachen.

+0

danke für Ihren Vorschlag. Ich hatte etwas in der Art von dem erwartet, was Sie in Ihrer ersten Lösung vorschlagen. Und ja, meine ID-Spalte enthält eindeutige Werte. –

+0

Ich verstehe nicht, was Sie meinen, indem Sie die Tabellenstruktur ändern; Grundsätzlich ist "id" bereits eine Auto-Increment-Spalte. Das Problem ist, dass die Reihenfolge der Zeilen von der Reihenfolge in der SELECT-Anweisung abhängt. Wie könnte mir eine zusätzliche Kolumne helfen? Habe ich etwas verpasst? –

+0

Wenn Sie keine Zeilen aus der Tabelle löschen, können Sie einfach "where id zwischen - 5 und + 5" verwenden. Dies würde die row_number() Berechnung eliminieren. Mit anderen Worten, die Lösung für Ihr Problem wäre nur ein Self-Join. –