verwendetes Datenbanksystem: SQL 2005 SP2 / VS 2005
Hallo zusammen,
ich habe ein eher allgemeines Problem mit SQL.
Genauer SQL Reporting.
Anhand von Berichtsparametern möchte ich Datensätze filtern bzw. wenn kein Parameter angegeben wird, möchte ich alle Daten sehen.
Jeder Filter der leer gelassen wird, muss mit einem „OR“ abgefangen werden um alle Datensätze ungefiltert zu erhalten.
([Tabelle].[Feld] = @Filter) OR (@Filter = NULL)
Genau dieses böse „OR“ nimmt das gesamte SQL Statement, kopiert es einmal davor und einmal dahinter (eben einmal das gesamte Statement mit Filter & einmal mit Parameter=NULL).
Aufgrund der vielen SubSelects(28stk) und der 12 Filterparameter kämen ich nach Adam Riese auf den 336fachen Quellcode.
Das kann ja nicht die Lösung sein…
Abgesehen davon, das wenn man diesen Berichtsparametern eine Tabelle hinterlegt, hat man garnicht die Möglichkeit einen Leeren Wert zu übergeben und alle Datensätze ungefilter anzeigen zu lassen.
Bin für jede Hilfe Dankbar, auch wenn das ganze (noch) nicht viel mit C# zu tun hat 🙂
Gruß,
TriB
Wenn ich das richtig verstehe hast Du eine Abfrage mit theoretisch 12 Parametern, die aber in allen möglichen beliebigen Kombinationen gesetzt/nicht gesetzt sein können und dann entsprechend in der Where-Bedingung der Abfrage berücksichtigt/nicht berücksichtigt werden dürfen?
Solche Sachen versuche ich immer in einer Stored Procedure mit Hilfe einer Temptabelle/Tabellenvariablen häppchenweise zu bearbeiten.
Als simples Beispiel: ich will alle Aufträge aus den letzten 3 Monaten, entweder alle oder nur die mit einer bestimmten Farbe.
Ich deklariere mir eine Tabellenvariable die hinterher zurückgegeben wird:
declare @tmp table (
AuftragsNr int,
Farbe varchar(20)
)
Ich füge ALLE Aufträge der letzten 3 Monate ein:
insert into @tmp (AuftragsNr, Farbe)
select AuftragsNr, Farbe from tbAuftraege where Datum > '2008-03-19'
Falls der Parameter "Farbe" gesetzt ist lösche ich alles mit der falschen Farbe einfach wieder raus:
if @FarbFilter <> ' alle'
begin
delete from @tmp where Farbe <> @FarbFilter
end
Und das mache ich dann halt für jeden einzelnen Filter so.
Und am Ende gebe ich meine gesamte Tabellenvariable zurück, als Datenquelle meines Berichtes:
select * from @tmp
Natürlich kann man das auch nicht in allen Fällen so anwenden, bei einer einigermaßen großen Datenmenge geht das nur wenn man zumindest einen oder zwei Filter hat die IMMER gesetzt sind, so daß man dann erstmal die Menge der Daten begrenzen kann die man einfügt.
So wie in meinem Beispiel das Datum, denn die Aufträge der letzten 3 Monate sind eine überschaubare Menge.
Das gleiche Prinzip nutze ich auch wenn ich Daten aus vielen verschiedenen Tabellen holen muß (vor allem in Verbindung mit Filtern) und eine Abfrage mit 15 Joins zu langsam ist.
Und zu der Tabelle als Berichtsparameter und dem leeren Wert - um mein Beispiel von oben mal fortzuführen würde ich für den @Farbfilter z.B. eine Tabelle mit Farben hinterlegen.
In der Tabelle ist natürlich normalerweise keine Farbe "alle", also füge ich meiner Abfrage einfach mit UNION eine hinzu:
select ' alle'
union
select Farbe from tbFarben
order by Farbe
Dadurch daß ' alle' mit einem Leerzeichen anfängt und ich nach Farbe sortiere, ist ' alle' automatisch der erste Wert in der Liste und fällt dem Benutzer sofort ins Auge.
Boahr, SUPER! Dank dir vielmals.
Habe gerade die " alle" Geschichte ausprobiert und sie funktioniert prima.
An das Stored Procedure werde ich mich dann aber erst nach dem Wochenende wagen 😉
Hast genau mein Problem verstanden und super erklärt.
Ich muss mir nur überlegen wie ich das am sinnvollsten in diese ganzen sub selects einbaue. Evtl. kann ich ja ähnliche Abfragen in einem Rutsch mit dem delete bearbeiten.
Schönes Wochenende,
TriB
Ähnliche Abfragen mit einem Rutsch? Nicht nötig.
Dadurch daß wir diese ganzen Operationen in einer Tabellenvariablen (also eine Variable im Hauptspeicher) machen sind die rasend schnell, deshalb kann man den Overhead durch die im Extremfall 12 einzelnen Delete-Abfragen vernachlässigen.
Deshalb nutze ich wirklich für jeden Filter eine eigene Abfrage.
Also z.B. so:
if @FarbFilter <> ' alle'
begin
delete from @tmp where Farbe <> @FarbFilter
end
if @MaxLaenge > 0
begin
delete from @tmp where Laenge > @MaxLaenge
end
usw.
Natürlich, wenn Du irgendwelche Sachen hast wo es sich anbietet kannst Du die ruhig zusammen mit einer Delete-Abfrage wegputzen, aber in den meisten Fällen wirst Du es eh einzeln machen müssen weil die Kombination welcher Filter gesetzt ist und welcher nicht sich ja jedes Mal ändern kann.