Benutzer mit den meisten Antworten
Verknüpfungs-Problem in einer View

Frage
-
Guten Abend zusammen,
ich habe eine View gebaut, die bestimmte Sachen zusammenfasst(Kategorien). Per Client hat der Admin die Möglichkeit, die Definition dieser Kategorien zu ändern/ergänzen.
Zu diesem Zweck gibt es eine Steuer-Tabelle, die per SQL Abfrage angesprochen wird (z.B. "...where Category in [1,4]..."). Diese Steuer-Tabelle ist mit 2 weiteren Steuer-Tabellen per Inner Join verknüpft, die ihrerseits wiederum mit Feldern der eigentlichen Daten-Tabellen -auch mittels Inner Join- verknüpft sind um die gewünschten Datensätze einer oder mehrerer Kategorien zu liefern.
Die gute Nachricht: alles funktioniert einwandfrei, aber... mit Krücken. Beobachten wir obige 2 "Untersteuertabellen":
Untersteuertabelle A hat die Spalten Wert1 und Wert2, wobei Wert1 den Integerwert der entsprechenden Kategorie enthält(verknüpft mit Wert1 der Hauptsteuertabelle) und Wert2 das Kriterium enthält, das mit der eigentlichen Datentabelle verknüpft ist. Da Tabelle A immer Werte enthält funktioniert dieser Teil problemlos z.B. Kategorie "1" und Name "Meier" liefert wie gewünscht. Das können auch mehrere sein, also z.B. Kategorie "1" und Name "Schulze" als weiteren Datensatz liefert dann beide.
Sorgenkind ist Untersteuertabelle B: Auch hier gibt es Wert1, der auch mit Wert1 der Hauptsteuertabelle verknüpft ist. Das Problem ist aber Wert2 (nennen wir die Spalte "Vorname"), der mit dem Vornamen der Datentabelle verknüpft ist.
Solange beispielsweise Kategorie "1" und Vorname "Hans" in der Untersteuertabelle B existiert, werden analog zu obigem Beispiel korrekt alle "Hans Meier" und "Hans Schulze" geliefert. Die Crux: Es kann der Fall eintreten, dass der Admin alle Vornamen mit einschließen will. Um diesen Fall auf der Benutzeroberfläche des Clients zu handhaben wurde per Konvention festgelegt, dass in der entsprechenden Kategorie-Definition kein Vorname angegeben wird, was dann bedeutet, dass alle eingeschlossen werden sollen. Dies widerspricht sich natürlich irgendwie. Denn wenn kein Vorname mit Kategorie "1" in Tab. B existiert, wird logischerweise für diese Kategorie nicht ein einziger Datensatz angesprochen.
Zunächst habe ich das Problem mittels eines Triggers gelöst, der (im Fall von 0 Einträgen für eine bestimmte Kategorie in Tab. B) eine Hilfstabelle veranlasst, sämtliche "Vornamen" zu aktivieren, die ihrerseits anstelle der Tab. B verknüpft wird.
Es ist klar, dass dieser Zustand sehr unschön ist, um nicht zu sagen unprofessionell ;) ganz abgesehen von Performance-Verlust.
Heute habe ich überlegt, ob denn ein "Wildcard" helfen könnte?? Kann denn eine Verknüpfung 2er Felder sowas erkennen, wenn ich in der Tabelle Kategorie "1" und Vorname "%" (oder *) eintrage und ich dann alle Vornamen bekomme?
Auf meiner Suche bin ich immer nur auf die where-Klausel gestoßen, wo man mittels like %... sowas auflösen kann. Dummerweise ist die fragliche Tabelle über eine SQL-Abfrage vom Client aber gar nicht erreichbar, sondern nur die Hauptsteuertabelle für die Kategorien.
Wenn es andere Lösungen gibt, sehr gerne.
Gruß Ron
- Bearbeitet ron61 Samstag, 18. Februar 2012 20:05
Antworten
-
Hallo Ron,
hat einen Moment gedauert.... Entschuldige.
Die derzeitige Lösung nutzt 6x einen CrossJoin über haupttable und category. Je nach Zeilenanzahl der beiden Tabellen kann das durchaus zu einer "Herausforderung" für die Performance werden...
Aus meiner Sicht wäre ein etwas anderer Ansatz vielleicht hilfreicher:
Zunächst einmal würde ich den CrossJoin in einen LEFT JOIN ändern und die Spalten verknüpfen, die verglichen werden:
SELECT x FROM haupttable LEFT OUTER JOIN kategorie cat ON haupttable.actyp = Cat.aircraft and haupttable.Version = Cat.Version and haupttable.servicetyp = Cat.styp
Danach würde ich den Vorteil der sequentiellen Abarbeitung der CASE-Anweisung nutzen:
CASE WHEN haupttable.actyp = Cat.aircraft and haupttable.FlugVersion = Cat.FlugVersion and haupttable.servicetyp = Cat.styp THEN category WHEN haupttable.actyp = Cat.aircraft and haupttable.servicetyp = Cat.styp and (cat.FlugVersion='' or cat.FlugVersion IS NULL) THEN category WHEN haupttable.servicetyp = Cat.styp and (cat.FlugVersion='' or cat.FlugVersion IS NULL) and(cat.aircraft='' or cat.aircraft IS NULL) THEN category WHEN haupttable.actyp = Cat.aircraft and haupttable.FlugVersion = Cat.FlugVersion and(cat.styp='' or cat.styp IS NULL) THEN category WHEN haupttable.actyp = Cat.aircraft and(cat.styp='' or cat.styp IS NULL) and(cat.FlugVersion='' or cat.FlugVersion IS NULL) THEN category ELSE 0 END AS category
Und schließlich würde ich das Ganze noch in eine Inline Table-Valued Function verpacken, die als Einstieg die Flugnummer hat und würde vor dem Join die relevante Anzahl der Datensätze in haupttable reduzieren. Die Abfrage würde dann so aussehen:
WITH Flug AS ( SELECT Flugnr,actyp,servicetyp,Version,WeitereSpalten FROM haupttable WHERE Flugnummer =@Flug ) SELECT Flug.*, CASE WHEN haupttable.actyp = Cat.aircraft and haupttable.Version = Cat.Version and haupttable.servicetyp = Cat.styp THEN category WHEN haupttable.actyp = Cat.aircraft and haupttable.servicetyp = Cat.styp and (cat.Version='' or cat.Version IS NULL) THEN category WHEN haupttable.servicetyp = Cat.styp and (cat.Version='' or cat.Version IS NULL) and(cat.aircraft='' or cat.aircraft IS NULL) THEN category WHEN haupttable.actyp = Cat.aircraft and haupttable.Version = Cat.Version and(cat.styp='' or cat.styp IS NULL) THEN category WHEN haupttable.actyp = Cat.aircraft and(cat.styp='' or cat.styp IS NULL) and(cat.Version='' or cat.Version IS NULL) THEN category ELSE 0 END AS category FROM Flug haupttable LEFT OUTER JOIN kategorie cat ON haupttable.actyp = Cat.aircraft and haupttable.Version = Cat.Version and haupttable.servicetyp = Cat.styp
Wenn das Ganze für mehere Flugnummern durchzuführen wäre, würde ich die oben beschriebene Funktion mit CROSS APPLY einbinden.- Als Antwort markiert ron61 Donnerstag, 1. März 2012 23:50
Alle Antworten
-
Hi,
wenn ich ehrlich sein soll, macht es mir deine Beschreibung unheimlich schwer, überhaupt auch nur irgendwas zu verstehen.
Könntest Du das nochmal schreiben und dabei dann bitte nicht mit Sachen wie "Untersteuertabelle1", "Spalten Wert1 und Wert2", ... arbeiten sondern mit etwas, was man sich auch plastisch vorstellen kann?
Im Idealfall postet Du bitte noch die Struktur der Tabellen inkl. PKs, FKs, den Code der View und das aktuelle sowie das eigentlich gewünschte Ergebnis mit beispielhaften Datensätzen.
Danke :)
Gruß, Stefan
Microsoft MVP - Visual Developer ASP/ASP.NET
http://www.asp-solutions.de/ - Consulting, Development
http://www.aspnetzone.de/ - ASP.NET Zone, die ASP.NET Community -
wenn ich ehrlich sein soll, macht es mir deine Beschreibung unheimlich schwer, überhaupt auch nur irgendwas zu verstehen.
Hallo Stefan, das tut mir leid und war natürlich nicht beabsichtigt. Ich gebe zu, dass ich aufgrund der wochenlangen Beschäftigung mit diesem Problem evtl. in meiner Beschreibung Dinge vorausgesetzt habe, die ein Außenstehender gar nicht weiß.
Machen wir es "kleingehackt" und auf den Kern des Problems reduziert. Ich habe zu diesem Zweck eine Test-Datenbank erstellt. Die enthaltenen Tabellen stellen das Problem -hoffentlich- dar. Da ich per Posting nur 2 Bilder laden kann, muss ich auch das stückweise machen. Aber es wird schon werden...
Um das Problem zu beschreiben, brauchen wir 4 Tabellen die ich folgendermaßen benennen möchte:
- Daten
- HauptSteuer
- Steuer1
- Steuer2
Die Verknüpfung innerhalb der Sicht, graphisch dargestellt, zeigt das folgende Bild:
Der zugehörige SQL Code lautet:
SELECT dbo.Daten.Vorname, dbo.Daten.Name, dbo.HauptSteuer.category FROM dbo.Daten INNER JOIN dbo.Steuer1 ON dbo.Daten.Name = dbo.Steuer1.Name INNER JOIN dbo.Steuer2 ON dbo.Daten.Vorname = dbo.Steuer2.Vorname INNER JOIN dbo.HauptSteuer ON dbo.Steuer2.category = dbo.HauptSteuer.category AND dbo.Steuer1.category = dbo.HauptSteuer.category
Inhalt und Struktur der Tabelle "Daten" wie folgt, wobei nur die Spalten "Vorname" und "Name" relevant sind:
Fortsetzung nächstes Posting
- Bearbeitet ron61 Sonntag, 19. Februar 2012 01:52
-
Teil2
hier Struktur und Inhalt der Tabelle "Hauptsteuer"
zuletzt Struktur und Inhalt der Tabellen "Steuer1" und "Steuer2"
Eine SQL-Abfrage "Select * from Testview where HauptSteuer.category = 1" liefert wie gewünscht
Vorname Name
Nils Schmidt
Nils Meier
Eine SQL-Abfrage "Select * from Testview where HauptSteuer.category = 2" liefert auch wie gewünscht
Vorname Name
Nils Mayer
Eine SQL-Abfrage "Select * from Testview where HauptSteuer.category = 3" liefert (das ist unerwünscht!!)
n i c h t s
ist aber logisch, da in der verknüpften Tabelle "Steuer2" keine "category=3" vorhanden ist.Anmerkung dazu: Die Tabelle "Steuer1" wäre in der Hirarchie "höherwertig".
Was muss ich tun, um folgende im Klartext gestellten 2 Bedingungen aufzulösen:
"Wenn in Tabelle 'Steuer1' eine Category erwähnt ist, und diese auch in der Tabelle 'Steuer2' erwähnt ist, dann verknüpfe 'Steuer2' wie gehabt."
"Wenn aber in Tabelle 'Steuer1' eine Category erwähnt ist, die NICHT in Tabelle 'Steuer2' erwähnt ist, dann nimm alle Datensätze die zur Verknüpfung mit "Steuer1" passen.
Die momentan erstellte Sicht gibt das natürlich nicht her. Und hoffentlich habe ich mein Problem nun so beschrieben, dass es verstanden werden kann.
Beste Grüße und schönes Wochenende
Ron
- Bearbeitet ron61 Sonntag, 19. Februar 2012 13:36
-
Ich bin mir nicht sicher, ob die derzeitige Sicht den gewünschten Effekt hat: nach der jetzigen Logik werden nur die Ergebnisse angezeigt, bei denen für einen Datensatz die Kategorien in Steuer1 und Steuer2 identisch sind. Im angegebenen Beispiel dürfte also "Hans Müller" nicht im Ergebnis auftauchen, da die Kategorien für "Hans" und "Müller" unterschiedlich sind.
Ich meine, daß eine separate Verknüpfung der Hauptsteuer-Tabelle sinnvoller ist:
SELECT Daten.Vorname, Daten.Name, HauptSteuer.category, HauptSteuer2.category FROM Daten INNER JOIN Steuer1 ON Daten.Name = Steuer1.Name INNER JOIN HauptSteuer ON Steuer1.category = HauptSteuer.category LEFT OUTER JOIN Steuer2 ON Daten.Vorname = Steuer2.Vorname LEFT OUTER JOIN HauptSteuer HauptSteuer2 ON Steuer2.category = HauptSteuer2.category;
Auf dieser Basis kannst Du dann entscheiden, welche Werte ausgegeben werden sollen. -
Hallo LMU92,
etwas ähnliches habe ich mir heute morgen auch ausgedacht. Noch eine Ergänzung zu dem oben gesagten. Wir bleiben mal bei diesem Beispiel und dem Inhalt meiner Test-Tabellen.
Was es zu erreichen gilt ist folgendes: Bei Abschicken des SQL Befehls vom Client
"Select * from Testview where HauptSteuer.category = 3" sollen alle Datensätze mit Name="Schulze" ausgegeben werden. Ich versuch's mal so wie Du vorgeschlagen hast.
Gruß Ron
-
Könntest Du uns evtl. ein paar Testdaten zusammenstellen? (Tabellen als CREATE TABLE..., Daten in der Form INSERT INTO SELECT UNION ALL und das erwartete Ergebnis als SELECT UNION ALL)
Anderenfalls können wir nur raten, was "zuviel" bedeutet... ;-)
MfG
Lutz
-
Die Lösung: Ich habe Änderungen an der Datenstruktur gemacht. Eine zusätzliche Spalte "Kategorie" in der relevanten Datentabelle wurde eingeführt. Ich zähle mal die Vorteile auf.
- 2 Tabellen mit einigen hunderten Einträgen wurden überflüssig
- 2 Trigger mit abenteuerlichen Verrenkungen wurden überflüssig
- Einiges an Code im Client wurde überflüssig
- 1 View wurde überflüssig
- fühlbare Performance-Verbesserung bei Abruf umfangreicher Daten.
- besser lesbarer Code in einer neu erstellten gespeicherten Prozedur
Das ganze läuft nun so ab: Unmittelbar nach dem Hochladen der Daten aus einer File wird o.g. Prozedur angestoßen. Diese setzt zunächst die Spalte "Kategorie" auf -1. Danach folgen insgesamt 5 Updates dieser Spalte unter Hinzuziehung 3 übrig gebliebener "Kategorie-Definitions-Tabellen" die ihrerseits verknüpft sind(und im Umfang erfreulich klein wurden). Diese 5 Updates beinhalten die Logik der von mir geforderten Art und Weise. Das stückweise Update bezieht sich immer nur auf noch nicht mit -1 belegten Spalten von "Kategorie". Dadurch wird der Kasten daran gehindert, bereits erfolgte Updates in vorigen Schritten wieder zunichte zu machen :))
Natürlich gibt es nun auch einen Nachteil: Die Kategorie ist nun statisch. Eine Änderung der Definition bedingt ein sofortiges neues Update. Aber was soll's. Das geht rasend schnell (ca. 1 Sec). Zudem sind solche Definitions-Änderungen eher selten. Das kann ich verschmerzen.
Dennoch hätte es mich aus purer Neugier interessiert, ob das eingangs erwähnte Problem anderweitig lösbar ist.
Erst mal Grüße und Danke für die Mühe
Ron
-
Prinzipiell zum von Dir dargestellten Vorgehen:
Wenn der Default-Wert der Kategorie-Spalte auf -1 gesetzt wird und via Insert diese Spalte nicht gefüllt wird, dann entfällt die erste Update-Anweisung. Ggf. lassen sich die 5 Updates auch weiter verdichten (verwenden von CASE-Anweisung oder die eher seltene Variante SET spalte = @variable = CASE.. ("Quirky update") ).
Die Anmerkung bzgl. der statischen Kategorie konnte ich nicht ganz nachvollziehen. Welche "Definition" kann geändert werden?
Und nun zu Deiner Anmerkung:
Dennoch hätte es mich aus purer Neugier interessiert, ob das eingangs erwähnte Problem anderweitig lösbar ist...
Wie bereits in meiner letzten Antwort dargelegt, würden wir hierzu ein kleines Test-Szenario mit Beispiel- und Ergebnisdaten benötigen. Ich bin zuversichtlich, daß sich das Ganze auch in einer View abbilden läßt.
MfG
Lutz
-
...würden wir hierzu ein kleines Test-Szenario mit Beispiel- und Ergebnisdaten benötigen...
Hallo Lutz,
also gut, machen wir kein Test-Szenario sondern das echte Problem: Mein Projekt befasst sich mit der Verwaltung von Flugplan-Daten einer "großen deutschen" Airline. Ziel ist es, dem/den Anwender(n) die für seinen Bereich benötigten Daten effizient anzubieten und ggf. für eine Weiterverarbeitung aufzubereiten.
Es hat sich im Verlauf der vergangenen Jahre, sogar Jahrzehnte, herausgestellt, dass es sinnvoll ist, diese Daten getrennt in Kategorien anzubieten, wobei jede Kategorie anwählbar und kombinierbar mit anderen ist. Deren gibt es insgesamt 6. Nehmen wir mal für unsere Diskussion die ersten 4.
- Passagierflüge-Schmalrumpf (z.B. 737)
- Passagierflüge-Großraum (z.B. A380)
- Frachtflüge
- Nachtluftpost-Flüge (momentan aber nicht aktuell)
Die Daten werden wöchentlich angeliefert. Als Grundlage dient immer die Flugnummer z.B. "XX1234" wobei "XX" die Airline repräsentiert. Die einzelnen Datensätze enthalten erschöpfende Auskunft über alle relevanten Einzelheiten, die ich nicht weiter vertiefen will. Wichtig ist eins: Alle Datensätze tragen einen Kennbuchstaben auf dem Rücken z.B. "F" für Frachter.
Es liegt auf der Hand, dass eine Software, die diese Kategorien anbietet, auch in der Lage sein muss, zu verwalten, was denn nun in welche Kategorie gehört. Was auf den ersten Blick einfach aussieht wird bei genauem Hinsehen zum Alptraum.
- Nicht jede Flugnummer, die "F" als Kennung hat ist auch ein Frachtflug
- Alle Flugnummern, die "M" (=Mail) als Kennung haben sind sicher ein Postflug, können aber Flugzeuge aus allen Kategorien sein
- Alle Flugzeuge der Kategorie 1 + 2 können (selten) auch in der Kategorie 3 fliegen (wobei sie dann tatsächlich ein "echtes" "F" als Kennung haben)
Dieser Alptraum ist aber lösbar. Nämlich durch Kombination der Kennung mit dem Flugzeug und ggf. der (Sitz, bzw. Fracht-)Version. Zu diesem Zweck gibt es ein schlichtes Fenster, wo die 3 relevanten Kriterien zur Kombinationen angeboten werden:
- Kennbuchstabe
- Flugzeug
- Version
Erschwerend kommt dazu, dass es mehrere gültige Kennbuchstaben für eine Flugnummer gibt. Aber auch das geht.
Nun muss ich zweifellos die Kombinationen in einer oder mehreren(?) Tabelle(n) hinterlegen. Fangen wir an:
- Ich hinterlege Kennung "F" und Flugzeug "M1F" für die Kategorie 3. Eine Version darf ich nicht hinterlegen, da diese differieren kann, und alle weiteren Versionen gültige Definitionen für Kategorie 3 darstellen. Version bleibt also frei (=NULL)
- Ich hinterlege Kennung "M" für Kategorie 4. Ein Flugzeug und Version darf ich nicht hinterlegen, da alle Flugzeuge mit allen Versionen gültig sind
- Ich hinterlege Kennung "F" und Flugzeug "321" und Version "P8" für Kategorie 3.
- Die gleiche Kennung "F" und das gleiche Flugzeug "321" ohne Versionsangabe ist aber nun für die Kategorie 1 vorgesehen.
- Damit uns nicht zu langweilig wird, müssen wir Kennung "J" und ebenfalls "321" ohne Version wiederum für Kategorie 1 hinterlegen.
- Einen Ausflug in die Kategorie 6 beschert uns die Hinterlegung keines Kennbuchstaben aber mit dem Transportmittel "ICE" (=Bahn - Ersatzverkehr) ohne eine Version.
Du merkst hoffentlich, was mein Problem ist. Mal hinterlege ich eine oder mehrere Informationen innerhalb einer Spalte, die als Kriterium für die Definition einer Kategorie dienen. Aber oft darf ich NICHTS hinterlegen, weil ALLE Daten, z.B. der Version des Transportmittels für die entsprechende Kategorie "freigegeben" sind. Es ist dem Anwender nicht zuzumuten, z.B. ALLE Versionen (momentan 435) für eine bestimmte Kategorie auszuwählen und zu hinterlegen. Das geht dann sowieso schief, weil beim nächsten Update vielleicht eine weitere Version dazukommt. Diese Datensätze würden dann sauber unter den Tisch fallen. Also hinterlegen wir im Falle von "ALLE" überhaupt keinen. Genau hier liegt der Knackpunkt. Diesen Widerspruch vermag der DB Server wohl nicht zu lösen, weil es unlogisch scheint.
Was ich mit "statischen Kategorie" meinte: Beim jetzigen Stand der Dinge hat jeder Datensatz die Angabe der Kategorie bei sich. Eleganter wäre es gewesen, wenn durch eine Tabellen-Verknüpfung die Kategorie "on the fly" ermittelt wird und im Fall einer Änderung der Definition einer Kategorie sofort wirksam ist.
Weiterhin sagst Du "...entfällt die erste Update-Anweisung..." Ja stimmt. Und was mach ich wenn sich die Definition ändert? Dann MUSS ich das so machen. Soll ich dafür 'ne weitere Prozedur machen? Sicher nicht ;)
Zum Abschluss den Code der gesp. Proz. wie er momentan läuft. Nach allen Regeln der Kunst getestet und 100% fehlerfrei von Anfang an. Das Objekt "kategorien" ist eine View die die Angaben der Kategorie-Definition enthält.
BEGIN SET NOCOUNT ON; --1 Setzen der Kategorie aller Datensätze auf Anfang-- update haupttable set kategorie=-1 --2 Setzen der Kategorie wo Version,Flugzeug,Servicetype die Kriterien bilden-- update haupttable set kategorie = category from kategorien as Cat where haupttable.actyp = Cat.aircraft and haupttable.version = Cat.version and haupttable.servicetyp = Cat.styp --3 Setzen der Kategorie wo Flugzeug,Servicetype die Kriterien bilden, das vorige Update bleibt unangetastet-- update haupttable set kategorie = category from kategorien as Cat where haupttable.actyp = Cat.aircraft and haupttable.servicetyp = Cat.styp and (cat.version='' or cat.version IS NULL) and kategorie = -1 --4 Setzen der Kategorie wo nur Servicetype die Kriterien bildet, die vorigen Updates bleiben unangetastet-- update haupttable set kategorie = category from kategorien as Cat where haupttable.servicetyp = Cat.styp and (cat.version='' or cat.version IS NULL)and(cat.aircraft='' or cat.aircraft IS NULL) and kategorie = -1 --5 Setzen der Kategorie wo Version, Flugzeug die Kriterien bilden, die vorigen Updates bleiben unangetastet-- update haupttable set kategorie = category from kategorien as Cat where haupttable.actyp = Cat.aircraft and haupttable.version = Cat.version and(cat.styp='' or cat.styp IS NULL) and kategorie = -1 --6 Setzen der Kategorie wo nur Flugzeug die Kriterien bildet, die vorigen Updates bleiben unangetastet-- update haupttable set kategorie = category from kategorien as Cat where haupttable.actyp = Cat.aircraft and(cat.styp='' or cat.styp IS NULL)and(cat.version='' or cat.version IS NULL)and kategorie = -1 END
Grüße und "guten Morgen"
Ron
-
Hallo Ron,
hat einen Moment gedauert.... Entschuldige.
Die derzeitige Lösung nutzt 6x einen CrossJoin über haupttable und category. Je nach Zeilenanzahl der beiden Tabellen kann das durchaus zu einer "Herausforderung" für die Performance werden...
Aus meiner Sicht wäre ein etwas anderer Ansatz vielleicht hilfreicher:
Zunächst einmal würde ich den CrossJoin in einen LEFT JOIN ändern und die Spalten verknüpfen, die verglichen werden:
SELECT x FROM haupttable LEFT OUTER JOIN kategorie cat ON haupttable.actyp = Cat.aircraft and haupttable.Version = Cat.Version and haupttable.servicetyp = Cat.styp
Danach würde ich den Vorteil der sequentiellen Abarbeitung der CASE-Anweisung nutzen:
CASE WHEN haupttable.actyp = Cat.aircraft and haupttable.FlugVersion = Cat.FlugVersion and haupttable.servicetyp = Cat.styp THEN category WHEN haupttable.actyp = Cat.aircraft and haupttable.servicetyp = Cat.styp and (cat.FlugVersion='' or cat.FlugVersion IS NULL) THEN category WHEN haupttable.servicetyp = Cat.styp and (cat.FlugVersion='' or cat.FlugVersion IS NULL) and(cat.aircraft='' or cat.aircraft IS NULL) THEN category WHEN haupttable.actyp = Cat.aircraft and haupttable.FlugVersion = Cat.FlugVersion and(cat.styp='' or cat.styp IS NULL) THEN category WHEN haupttable.actyp = Cat.aircraft and(cat.styp='' or cat.styp IS NULL) and(cat.FlugVersion='' or cat.FlugVersion IS NULL) THEN category ELSE 0 END AS category
Und schließlich würde ich das Ganze noch in eine Inline Table-Valued Function verpacken, die als Einstieg die Flugnummer hat und würde vor dem Join die relevante Anzahl der Datensätze in haupttable reduzieren. Die Abfrage würde dann so aussehen:
WITH Flug AS ( SELECT Flugnr,actyp,servicetyp,Version,WeitereSpalten FROM haupttable WHERE Flugnummer =@Flug ) SELECT Flug.*, CASE WHEN haupttable.actyp = Cat.aircraft and haupttable.Version = Cat.Version and haupttable.servicetyp = Cat.styp THEN category WHEN haupttable.actyp = Cat.aircraft and haupttable.servicetyp = Cat.styp and (cat.Version='' or cat.Version IS NULL) THEN category WHEN haupttable.servicetyp = Cat.styp and (cat.Version='' or cat.Version IS NULL) and(cat.aircraft='' or cat.aircraft IS NULL) THEN category WHEN haupttable.actyp = Cat.aircraft and haupttable.Version = Cat.Version and(cat.styp='' or cat.styp IS NULL) THEN category WHEN haupttable.actyp = Cat.aircraft and(cat.styp='' or cat.styp IS NULL) and(cat.Version='' or cat.Version IS NULL) THEN category ELSE 0 END AS category FROM Flug haupttable LEFT OUTER JOIN kategorie cat ON haupttable.actyp = Cat.aircraft and haupttable.Version = Cat.Version and haupttable.servicetyp = Cat.styp
Wenn das Ganze für mehere Flugnummern durchzuführen wäre, würde ich die oben beschriebene Funktion mit CROSS APPLY einbinden.- Als Antwort markiert ron61 Donnerstag, 1. März 2012 23:50
-
Hallo Ron,
hat einen Moment gedauert.... Entschuldige.
Hallo Lutz,
ICH bin es der in Deiner "Schuld" steht :) Ich habe zwar momentan wenig Zeit, möchte es aber nicht versäumen Dir für die Mühe zu danken, und vor allem meinen Hut zu ziehen: Du scheinst an alles gedacht zu haben.
Ich werde mir alles in Ruhe ansehen und (evtl. heute Abend) berichten.
Gruß Ron
-
Hallo Lutz,
nachdem ich in meinem schlauen Buch das Kapitel Inline - Funktion durch habe, sehe ich etwas klarer und verstehe -fast- alles, was in Deinem Ansatz an Überlegungen steckt. Das deckt sich mit meinem ursprünglichen Vorhaben.
Leider habe ich eine Unterlassungs-Sünde begangen: Ich habe bisher verschwiegen, die Tabelle "haupttable" hat einen etwas irre führenden Namen. Zwar stecken dort die meisten Informationen drin(deswegen nannte ich sie so), aber einige wenige Daten (wie z.B. die Flugnummer) stecken in einer verknüpften Tabelle mit Namen "fltnbr", die mit "haupttable" 1:n verknüpft ist. "haupttable" stellt also die Detailtabelle dar. Hintergrund: Bei einem Flug über mehrere Streckenabschnitte(in "haupttable" hinterlegt) wird sich die Flugnummer nicht ändern. Auch die Art des Fluges (inbound oder outbound bezogen auf den Heimatflughafen) wird sich nicht ändern. Soviel dazu.
Die Informationen, die darüber entscheiden um welche Kategorie es sich handelt, liegen in der "haupttable", wie z.B. der Flugzeugtyp.Die Verknüpfung dieser beiden Tabellen für die momentane Sicht lautet:
SELECT TOP (100) PERCENT dbo.fltnbr.fugnummer, dbo.fltnbr.isInbound, dbo.fltnbr.isOutbound, dbo.haupttable.actyp, dbo.haupttable.servicetyp, dbo.haupttable.version, dbo.haupttable.zaehler,weitereFelder FROM dbo.fltnbr INNER JOIN dbo.haupttable ON dbo.fltnbr.zaehler = dbo.haupttable.zaehler
Dies liefert also noch keine Kategorie. Zur Erinnerung, Ziel ist es, vom Client aufzurufen:
Select * from myView where Category=0 and ....(weitere Bedingungen)
Anmerkung: Category=0-5 (nullbasiert)
Du schreibst oben "als Einstieg die Flugnummer"... das ist ein Missverständniss ! Ich will lediglich die Category aufrufen können und DANN alle entsprechenden Datensätze mit Flugnummern (und Detail-Angaben) geliefert bekommen.
Die Definitionen der Kategorien ist nunmehr in 3 Tabellen übriggeblieben deren Verknüpfung (was ich als View hinterlegt habe) Du ja schon kennst. Das ist "kategorien". Offenbar gibt es in Deinem Ansatz da einen Schreibfehler. Da fehlt ein "n". Bei Dir heißt es
LEFT OUTER JOIN kategorie cat
Was ich dann wahrscheinlich auch ändern muss ist der "with" Block, da die Flugnummer nun nicht mehr als Kriterium dient. Ich versuch mich mal weiter dran. Leider muss ich noch alle Algorythmen, die ich im Kopf habe mehr oder weniger wörtlich in SQL "übersetzen" da ich noch nicht so virtuos in SQL "denken" kann ;)
Bis bald und nochmals danke für Deinen Ansatz.
Gruß Ron
-
Nun also doch zurück zu "Plan B". Ich muss bei meiner Variante eines updates bleiben, weil der -scheinbare- Widerspruch für das T-SQL nicht auflösbar ist. Nachdem ich also bei der ursprünglichen Update-Version einige Feinjustierungen gemacht habe, läuft alles perfekt.
Das "Performance" Problem, was Lutz angesprochen hat, ist nicht wirklich eins. Einmal pro Woche 1 Sec. ich glaub das will niemand wissen ;)
Danke für die Vorschläge
Ron