Fragensteller
Datenmenge und Sortierungen

Frage
-
Moin Leute,
ich stelle von meiner alten Datenspeichertechnik um auf SQL-Server und bin da noch nicht richtig zu Hause. Nun hab ich ein Problem und bin mir nicht sicher ob das überhaupt so geht und ob ich die richtige SQL-Denke hab. Auf jeden Fall braucht mein User eine adäquate Lösung.
Da passiert einfach folgendes: DBF-Datei, der User gibt eine Arbeitsnummer (AN, char) ein , diese wird via Index AN gefunden und dann setze ich einen anderen (vorhandenen) Index namens Ordnung (=Feld1+Feld2+AN) und der User kann dann ausgehend von dem gefundenen Satz in diesem Bereich blättern.
Wie kriege ich denn sowas in SQL hin? Also eine Teilmenge aus einer Tabelle fischen, Zeiger steht auf einem gesuchten Satz (eben dem mit der gesuchten (AN) und "davor" und "dahinter" stehen 20, 30,40 Sätze nach einer anderen Ordnung ?
Geht das überhaupt so? performant muss das natürlich auch noch sein.
Grüsse von der WeserHorst
Alle Antworten
-
nun ja, dann wirst Du damit auch nie etwas tun.( Auslaufmodell leider )
Aber mal ganz davon abgesehen: Ich vereinfache mein Problem mal. Ganz einfach gefragt: ich suche einen Satz mit :
select * from tabelle where AN = Usereingabe.
und ich weiß das damit nur ein Satz gefunden wird (AN gibt es jeweils nur einmal).(oder keiner)
Gibt es dann eine Möglichkeit durch eine Erweiterung des Select-Befehls diesen Satz und 20 weitere zu holen die einem 'order by AN' entsprächen?
Ich hab so das dumme Gefühl das geht garnicht und auch das es irgendwie verdammt kompliziert ist wenn die Tabelle selber keinen Index kennt.
Irgendwie ist mir die Philosophie wohl noch zu fremd.
Dabei ist die Problemstellung eigentlich simpel: der User möchte durch Teile seiner Daten nach einer bestimmten Ordnung durchblättern.
Aber eben nur durch Teile und wo er beginnen muss bestimmt er durch die Eingabe.Vielleicht hast Du (oder irgendwer?) ja trotzdem einen allgemeinen Tipp (oder einen Literaturhinweis: Datensalat für Dummmies oder so)
-
Hallo Horst,
seit der Version 2005 gibt es die sogenannten Window Functions. Aktuell gibt es auch noch ein Buch dazu, das erste Kapitel ist auch kostenlos:
http://www.insidesql.org/blogs/cmu/sql_server/high-performance-tsql-window-functionsDu könntest über ROW_Number() einen Paging Mechanismus implementieren, oder ab 2012 mit OFFSET/FETCH arbeiten.
Das hier habe ich auf die schnelle gefunden:
http://beyondrelational.com/modules/2/blogs/28/posts/10434/sql-server-server-side-paging-with-rownumber-function.aspx
Einen schönen Tag noch,
Christoph
--
Microsoft SQL Server MVP
www.insidesql.org/blogs/cmu -
Ich danke Dir Christoph,
das sieht alles sehr interessant aus und ich werd mich gleich mal intensiver damit beschäftigen. Ich denke aber das ich diese Infos auf jeden Fall gebrauchen kann da ich nicht nur eine Umsetzung habe sondern zukünftig sowieso viel mit dem SQL(-Server) zu tun habe.( Und dann auch mit C#).
Dir auch noch einen schönen Tag :-))
Horst
-
Hallo Horst,
ich arbeite auch mit VFP und nutze den SQL-Server seit fast zehn Jahren. Ich bin bisher noch auf kein Problem gestossen, welches mit dem SQL-Server nicht vergleichbar zu lösem wäre. Das meiste geht wesentlich eleganter.
Indizes brauchst Du auf dem SQL-Server nur zur Beschleunigung der Zugriffe, nicht zur Sortierung der Abzeige.
Wie selektierst Du denn jetzt?
Wenn Du ein Filterkriterium über mehrere Felder brauchsr kannst Du z.B. eine View benutzen.
CREATE VIEW myView AS SELECT *,Feld1+feld2+AN AS ordnung FROM ...
Dein SQL-Statement müsste dann so aussehen
SELECT TOP 20 * FROM myView WHERE ordnung ...
Das ist alles ist aber sehr theoretisch, gib doch einmal ein Beispiel. Bei der Eingabe einer AN sollen welche DS angezeigt werden?
Gruss Uli
- Bearbeitet Uli Münch Donnerstag, 14. Juni 2012 06:14
-
Hallo Ulli,
sorry, wenn ich jetzt erst antworte. Ich hatte direkt nach dem Posting einen Noteinsatz, ein intensives Familien-WE und Montags musste ich zum Kunden. Wo die Zeit so bleibt ist einfach grauenhaft. Nun werd ich mich wieder mit diesem Problem beschäftigen. Dein erster Absatz macht mir richtig Mut. Insgesamt hab ich ja doch ein wenig Sorgen wie das mit der Performance alles so aussehen wird. Ganz nebenbei: ich arbeite ja mit VFX und CA und will dann die Lösung auch irgendwie da mit einbauen. Aber das dürfte kein grosses Problem sein hoffe ich. Fritz hat mir auch schon eine Lösung gepostet. Ich beschreib aber mein Problem trotzdem nochmal, vielleicht hast Du ja noch eine Bemerkung, Verbesserung, Ablehnung oder anderen Kommentar dazu. Ich muss und ich will auf jeden Fall dazulernen weil ich in Zukunft nur noch auf dem SQL-Server speichere und die nativen Tabellen nur noch in Ausnahmefällen zulässig sind.
Also: Die Daten kommen auf verschiedenen Wegen in die Tabelle. Der User kennt nur die AN die eindeutig! ist. In diesem eindeutigen Satz befinden sich die Felder Feld1 und Feld2 die das nicht sind und die der User nicht kennt und deren Gruppe die eigentliche Datenumgebung ist wo der User hinwill. In Fox mache ich das ganz einfach:
set order to AN
seek UsereingabeAN
set order to Ordnung (=Feld1+Feld2+AN)
und fertig. Nun kann er in seiner gewünschten Datenumgebung rauf und runter blättern.
Die Lösung ist wohl: mit der Eingabe den einen Satz via
"select ..where Usereingabe = AN into cursor Zwi" in einen Zwischencursor holen, via
"select.. where Feld1 = zwi.Feld1 AND Feld2 = zwi.Feld2 " dann die endgültigen Daten holen. Hört sich jetzt so einfach an, aber mit meiner Fox-Denke (s.o.) wars erstmal kompliziert. Und wie wird die Perfomance sein ? ich werd mal rangehen ...... oder weißt Du was besseres ?Auf jeden Fall Danke für deine Antwort und schönes WE
Horst
-
Hallo Horst,
mir fehlt immer noch ein wenig die Logik dieses Vorgehens. Du solltest Dir evtl. einmal die LIKE-Klausel anschauen, hier kannst Du Platzhalter u.ä. verwenden.
http://msdn.microsoft.com/de-de/library/ms179859.aspx
Denkbar wäre auch
SELECT * FROM mytable WHERE feld1 IN (SELECT feld1 FROM mytable WHERE an = < Usereingabe>)
oder so
SELECT * FROM mytable WHERE feld1+feld2 IN (SELECT feld1+feld2 FROM mytable WHERE an = < Usereingabe>)
Probier es doch einfach einmal aus.
Gruss Uli
-
Hallo Ulli
Danke Dir wirklich für Deine Mühe. Das Problem löse ich inzwischen mit einem Zwischencursor und bei mir sieht die Performance auch ganz gut aus.
>>SELECT * FROM mytable WHERE feld1+feld2 IN (SELECT feld1+feld2 FROM mytable WHERE an = < Usereingabe>)
Dieser Vorschlag ist auch gangbar, vielleicht baue ich (je nach performance beim Kunden auch noch mal um).
Mir ist allerdings aufgefallen das ich auch zuviel in den Datenstrukturen des Kunden denke mittlerweile (die ich ganz gut kenne). Wenn alles etwas anders gelagert wäre würde das so nicht funktionieren.Aber des Lerneffektes halber würde mich jetzt noch folgendes interessieren (aber beschäftgie Dich bitte nur damit wenn Du auch die Zeit hast! das Problem für die Kundendaten ist erstmal gelöst, keine Zeitbombe mehr für mich, ich will nicht aus lauter Jux und Tollerei anderen Arbeit beschaffen :-)))
Also:
Satz An Feld1 Feld2
1 1 Otto Hamburg
2 2 Otto Hamburg
3 3 Otto Dortmund
4 4 Karl Berlin
5 5 Karl München
6 6 Emil Dortmund
Angenommen der User kennt nur die An = 3. Wäre es dann trotzdem möglich diese Sätze (geordnet nach Feld1+Feld2+An) mit einem Select -Befehl zu erhalten? In Fox würde fogendes passieren: Satzzeiger landet bei Satz 3. Index auf Feld1+Feld2+An gesetzt, sähe die Sache so aus:
Satz An Feld1 Feld2
6 6 Emil Dortmund
4 4 Karl Berlin
5 5 Karl München
3 3 Otto Dortmund
1 1 Otto Hamburg
2 2 Otto Hamburg
Wie Du siehst passt der Karl garnicht ins Bild (weder Otto noch Dortmund), ich will aber alle Sätze beim Durchblättern so haben.Und halt noch 10 "drunter" und "drüber" . Machbar???
Grüsse von der Weser
Horst
-
Hallo Horst,
machbar ist alles. Wenn Du die View_ordnung aus dem folgenden Code auf Deiner DB anlegst, sollte das Ergebnis des letzten Statements ziemlich Deinem Anliegen entsprechen.
Ich würde allerdings diese Statement in eine Proc oder Func packen um diese Abrage nur einmal ausführen zu müssen
(SELECT ranking FROM view_ordnung where an = @usereingabe)
Gruss Uli
IF NOT EXISTS ( SELECT * FROM sys.tables
JOIN sys.schemas ON sys.tables.schema_id = sys.schemas.schema_id
WHERE sys.tables.name = N'test' )
BEGIN
CREATE TABLE test
(an int,feld1 varchar(30) ,feld2 varchar(30) )
insert into test (an,feld1,feld2)VALUES(1,'Otto','Hamburg')
insert into test (an,feld1,feld2)VALUES(2,'Otto','Hamburg')
insert into test (an,feld1,feld2)VALUES(3,'Otto','Dortmund')
insert into test (an,feld1,feld2)VALUES(4,'Karl','Berlin')
insert into test (an,feld1,feld2)VALUES(5,'Karl','München')
insert into test (an,feld1,feld2)VALUES(6,'Emil','Dortmund')
END
GO
/*
IF object_id(N'dbo.view_ordnung', 'V') IS NOT NULL
DROP VIEW dbo.view_ordnung
*/
create view dbo.view_ordnung as select rank()OVER (ORDER BY a.feld1, a.feld2) as ranking, * from test a
GO
DECLARE @usereingabe int
set @usereingabe= 3
select an,feld1,feld2 from view_ordnung where ranking between (SELECT ranking FROM view_ordnung where an = @usereingabe)-10
and (SELECT ranking FROM view_ordnung where an = @usereingabe)+10
DROP VIEW dbo.view_ordnung
DROP TABLE test
- Bearbeitet Uli Münch Donnerstag, 28. Juni 2012 08:06