none
where klauseln oder gespeicherte prozedur oder ?? RRS feed

  • Frage

  • Guten Tag zusammen, zunächst die gute Nachricht: Ich bin überrascht über die Leistungsfähigkeit der beiden Pakete Visual c++ 2010 express/sql server 2008 R2 (mit management tools), was ich mir beides vor kurzem zugelegt habe.

    Besonders erfreulich ist der Nulltarif :) Der Wermuts-Tropfen ist der nicht vorhandene SQL Server-Explorer im Visual Studio. Damit konnte ich zwar leben, man muss halt alles "Händisch" machen, aber ich bin an einer Stelle angekommen, wo ich um Rat fragen möchte.

    Es geht um diverse Abfragen, wo durch den Benutzer einige komplexe Prozesse angestoßen werden müssten, die auf der Benutzeroberfläche eigentlich harmlos aussehen, aber in Wirklichkeit einen regelrechten Rattenschwanz an "select / where / join" Klauseln auslösen würden um das gewünschte Resultat zu sehen.

    Das Problem: Natürlich, ich könnte je nach Auswahl des Benutzers mit seinen Checkboxen, Listboxen usw.. einen "Select ...." String basteln, aber das ist extrem fehlerträchtig. Zudem habe ich bei ersten Tests erschreckend feststellen müssen, dass das Ergebnis unter Umständen weniger Zeichen beinhaltet als der Abfragestring selbst ;) Datenmenge insgesamt ca. 70.000 Zeilen.

     

    Einen Teil meiner Probleme konnte ich zwar zunächst dadurch lösen, dass ich einen gesonderte Tabelle durch den User mit "insert" befüllen ließ (die durch ein "join" mit weiteren Tabellen die gewünschten Resultate liefert) aber das kann es auch nicht sein, da diese Tabelle vor dem "insert" geleert werden muss. Ganz abgesehen von dem exzessiven Anstieg des Log-Files. Was tun? Gespeicherte Prozedur erstellen und anstoßen? Trigger? Wäre nett, wenn ein Denkanstoß käme.

    Danke im Voraus Ron


    Dienstag, 6. Dezember 2011 21:41

Antworten

  • Hallo Ron,

    was das Auswählen aller Zeilen angeht ginge das z. B. über eine EXISTS Klausel:

    SELECT Detail.* 
    FROM HauptTabelle AS Haupt
    INNER JOIN DetailTabelle AS Detail ON Haupt.ID = Detail.HauptID
    WHERE EXISTS(SELECT * 
    	FROM DetailTabelle AS DetailKriterium
    	WHERE DetailKriterium.HauptID = Haupt.ID 	-- Verknüpft mit der Haupttabelle
    		AND DetailKriterum.EineSpalte = 4711);	-- zusätzliches Kriterium
    
    


    wobei in dem Falle die DetailTabelle zweimal mit unterschiedlichem Alias verwendet wird.
    Es könnte aber auch eine ganz andere Tabelle sein.

    Ein Beispiel auf Basis der Northwind Beispiel-Datenbank:

    SELECT od.*, o.CustomerID, p.ProductName
    FROM dbo.[Orders] AS o 
    INNER JOIN dbo.[Order Details] AS od ON o.OrderID = od.OrderID
    INNER JOIN dbo.Products AS p ON od.ProductID = p.ProductID
    WHERE EXISTS (SELECT *
    		FROM dbo.[Order Details] AS odp 
    		WHERE o.OrderID = odp.OrderID -- alternativ od.OrderId = odp.OrderID
    			AND	odp.ProductID = (SELECT ProductID 
    				FROM dbo.Products 
    				WHERE ProductName = N'Raclette Courdavault'))
    
    


    womit alle Aufträge-Details anzeigt werden, wo zumindest einmal das Produkt "Raclette Courdavault" enthalten ist.

    Gruß Elmar

    P. S.: Wenn Du weitere Fragen dazu hast,  solltest Du einen neuen Thread aufmachen,
    damit es übersichtlich bleibt.

    Freitag, 16. Dezember 2011 13:27
  •  

    Hallo,

    arbeite bitte mal die beiden Artikel von Erland Sommarskog durch:

    The Curse and Blessings of Dynamic SQL
    (eine ältere deutsche Übersetzung von Frank Kalis: Dynamisches SQL : Fluch und Segen)
    und Dynamic Search Conditions in T-SQL<small></small>

    Mit dem Hintergrundwissen solltest Du generell für das erstellen "hochdynamischer" Abfragen gerüstet sein.

    Am Ende bleibt es einem überlassen, ob man es in T-SQL oder in C++ erledigt.
    C++ (oder auch .NET) hat einige Vorteile, was Zeichenoperationen angeht,
    auch kann man dort über Methoden / Klassen sich die Arbeit erleichtern -
    T-SQL ist da leider nicht sehr weit entwickelt.

    Das SQL Anweisungen schon mal umfangreich werden können, liegt in der Natur der Sprache.
    Durch Sichten und mit Tabellenfunktionen kann man wiederholt genutzte Elemente zusammenfassen.

    Wenn Du meinst mit einer Zwischentabelle besser klarkommen zu können,
    so kann man dies auch über temporäre Tabellen lösen. Wobei man immer abwägen sollte,
    ob eine (längere) Abfrage nicht günstiger ist.

    Gespeicherte Prozeduren können helfen, Befehle zusammenzufassen und bieten zudem Vorteile,
    wenn es um die Absicherung der Zugriffe geht - aber das muss nicht unbedingt sein,
    denn Du kannst auch mehrere Befehle als Stapel übertragen.

    Gruß Elmar

    Dienstag, 6. Dezember 2011 23:40

Alle Antworten

  •  

    Hallo,

    arbeite bitte mal die beiden Artikel von Erland Sommarskog durch:

    The Curse and Blessings of Dynamic SQL
    (eine ältere deutsche Übersetzung von Frank Kalis: Dynamisches SQL : Fluch und Segen)
    und Dynamic Search Conditions in T-SQL<small></small>

    Mit dem Hintergrundwissen solltest Du generell für das erstellen "hochdynamischer" Abfragen gerüstet sein.

    Am Ende bleibt es einem überlassen, ob man es in T-SQL oder in C++ erledigt.
    C++ (oder auch .NET) hat einige Vorteile, was Zeichenoperationen angeht,
    auch kann man dort über Methoden / Klassen sich die Arbeit erleichtern -
    T-SQL ist da leider nicht sehr weit entwickelt.

    Das SQL Anweisungen schon mal umfangreich werden können, liegt in der Natur der Sprache.
    Durch Sichten und mit Tabellenfunktionen kann man wiederholt genutzte Elemente zusammenfassen.

    Wenn Du meinst mit einer Zwischentabelle besser klarkommen zu können,
    so kann man dies auch über temporäre Tabellen lösen. Wobei man immer abwägen sollte,
    ob eine (längere) Abfrage nicht günstiger ist.

    Gespeicherte Prozeduren können helfen, Befehle zusammenzufassen und bieten zudem Vorteile,
    wenn es um die Absicherung der Zugriffe geht - aber das muss nicht unbedingt sein,
    denn Du kannst auch mehrere Befehle als Stapel übertragen.

    Gruß Elmar

    Dienstag, 6. Dezember 2011 23:40
  • Hallo ron61,

    Ich gehe davon aus, dass die Antwort Dir weitergeholfen hat.
    Solltest Du noch "Rückfragen" dazu haben, so gib uns bitte Bescheid.

    Grüße,
    Robert

    Freitag, 16. Dezember 2011 09:53
    Moderator
  • Hi Robert, und ein "dankeschön" an Elmar, dessen Links mir viel gebracht haben.  Ein DB Server ist eben doch eine ganz andere Baustelle als ein Solo-Auftritt einer "normalen" Anwendung. Insbesondere was die Kommunikation mit dem Client betrifft. Als relativer Neuling in Sachen DB tue ich mich da noch etwas schwer.

    Ich muss auch gleich um Nachsicht bitten. Es hat etwas gedauert, bis ich mich hier wieder melde. Ich wollte mit Ergebnissen kommen. Vor 2 Tagen gab es den Durchbruch :) Die Lösung für eine ganze Reihe von "Problemen" lag die ganze Zeit vor mir, ohne dass ich es wahrgenommen habe. Ein schlichtes "inner - join" mit 4 Tabellen beseitigte nicht nur die Notwendigkeit von etwaigen Prozeduren, die dann eine sinnlose Arbeit verrichtet hätten (weil es so viel eleganter geht). Auch der Aufruf aus dem Client wurde massiv entschärft und wurde recht schlicht. Auch das "Zwischenlagern" in einer temporären Tabelle entfiel.

    Lediglich eine zusätzliche Tabelle musste ich zur Auflösung einer n:m Beziehung schaffen. Das war's (ganze 6 Einträge stehen da drin :) Last not least habe ich beim Zusammensetzen des Abfragestrings mittels des Mengenoperators IN weitere Ordnung und Übersicht geschaffen.

    Ein einziger Stolperstein ist noch übriggeblieben. Möglicherweise werde ich da um den Einsatz eines Cursors nicht herumkommen. Vielleicht hat jemand eine andere Idee? Hier das Szenario:

    Es gibt -wie so oft- eine "Haupttabelle" mit eindeutigen Einträgen und eine "Detailtabelle" die mittels Fremdschlüssel (1:n) aneinandergebunden sind. Es funktioniert auch alles wie am Schnürchen. Nun gibt es aber folgende Situation, wo der Benutzer nach bestimmten Einträgen in der Detailtabelle suchen möchte. Nehmen wir an, der gesuchte Eintrag befindet sich in der dritten Zeile (relativ zum Haupttabellen-Eintrag betrachtet) der Detailtabelle. Nun wird mir natürlich als Ergebnis nur diese eine Zeile angezeigt. Das ist soweit ja in Ordnung. Der Server hat brav gemacht was ich ihm auftrug. ABER es sollten dann ALLE Detail-Zeilen, die zu dem Haupttabellen-Item gehören, angezeigt werden. Im vorigen Beispiel also auch Zeile 1+2 und dann die Zeile wo der gesuchte Eintrag steht, sowie evtl. weitere Zeilen (max. ca. 4-5) der Detailtabelle (die ebenfalls zu diesem Haupttabelleintrag gehören).

    Möglicherweise mit einer geschachtelten SELECT Anweisung? Ich hab da schon etwas experimentiert, hatte aber bisher keine Erfolg. Nochmals danke an Elmar für die Hilfestellung.

     

    Ron

    Freitag, 16. Dezember 2011 11:47
  • Hallo Ron,

    was das Auswählen aller Zeilen angeht ginge das z. B. über eine EXISTS Klausel:

    SELECT Detail.* 
    FROM HauptTabelle AS Haupt
    INNER JOIN DetailTabelle AS Detail ON Haupt.ID = Detail.HauptID
    WHERE EXISTS(SELECT * 
    	FROM DetailTabelle AS DetailKriterium
    	WHERE DetailKriterium.HauptID = Haupt.ID 	-- Verknüpft mit der Haupttabelle
    		AND DetailKriterum.EineSpalte = 4711);	-- zusätzliches Kriterium
    
    


    wobei in dem Falle die DetailTabelle zweimal mit unterschiedlichem Alias verwendet wird.
    Es könnte aber auch eine ganz andere Tabelle sein.

    Ein Beispiel auf Basis der Northwind Beispiel-Datenbank:

    SELECT od.*, o.CustomerID, p.ProductName
    FROM dbo.[Orders] AS o 
    INNER JOIN dbo.[Order Details] AS od ON o.OrderID = od.OrderID
    INNER JOIN dbo.Products AS p ON od.ProductID = p.ProductID
    WHERE EXISTS (SELECT *
    		FROM dbo.[Order Details] AS odp 
    		WHERE o.OrderID = odp.OrderID -- alternativ od.OrderId = odp.OrderID
    			AND	odp.ProductID = (SELECT ProductID 
    				FROM dbo.Products 
    				WHERE ProductName = N'Raclette Courdavault'))
    
    


    womit alle Aufträge-Details anzeigt werden, wo zumindest einmal das Produkt "Raclette Courdavault" enthalten ist.

    Gruß Elmar

    P. S.: Wenn Du weitere Fragen dazu hast,  solltest Du einen neuen Thread aufmachen,
    damit es übersichtlich bleibt.

    Freitag, 16. Dezember 2011 13:27
  • Hallo Ron,

    was das Auswählen aller Zeilen angeht ginge das z. B. über eine EXISTS Klausel:


    Ja, nun hab ich's !! Das war der Punkt den ich übersehen habe (Hätt ich auch selber draufkommen müssen, mmmhh..dabei hatte ich die EXISTS Klausel schon kennengelernt).

    Allerdings musste ich das ganze etwas umbauen, da das von Dir völlig richtig erkannte "inner join" (mit weiteren joins) bereits in einer Sicht realisiert wurde, die letztlich an den Benutzer ausgeliefert wird.

    Erfreulicherweise kann man ja eine Sicht wie eine "normale" Tabelle behandeln. Daher lasse ich vom Client nun so aufrufen:

    SELECT * FROM myView AS haupt
    	WHERE EXISTS(SELECT * FROM myView AS Detail
    		WHERE Detail.zaehler = haupt.zaehler AND 
    			((Detail.irgendwas = '4711')or (Detail.nochirgendwas='4712')))
    				AND schonwiederwas=0 ... order by bla, blubb
    


    Funktioniert wie eine Eins !! Besten Dank für die Unterstützung.

    Zwar habe ich neue "Baustellen" entdeckt, die aber nichts mit obigem zu tun haben. Wenn ich da nicht weiterkomme, mache ich neuen Thread auf.

    Gruß Ron

    Freitag, 16. Dezember 2011 20:57