none
Verknüpfungs-Problem in einer View RRS feed

  • 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
    Samstag, 18. Februar 2012 20:04

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
    Donnerstag, 23. Februar 2012 10:40

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

    Samstag, 18. Februar 2012 21:20
    Moderator
  • 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:

    1. Daten
    2. HauptSteuer
    3. Steuer1
    4. 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
    Sonntag, 19. Februar 2012 01:24
  • 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
    Sonntag, 19. Februar 2012 01:43
  • 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.

    Sonntag, 19. Februar 2012 14:41
  • 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

    Sonntag, 19. Februar 2012 15:02
  • So, nun habe ich alle möglichen Varianten probiert. Leider ohne Erfolg. Entweder "schweigt" die Kategorie = 3 oder ich bekomme bei 1 und/oder 2 zuviele Datensätze :( Nun ist Suche nach dem Strohhalm angesagt.

    Gruß Ron

    Montag, 20. Februar 2012 00:45
  • 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

    Montag, 20. Februar 2012 06:28
  • 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

    Dienstag, 21. Februar 2012 23:11

  • 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

    Dienstag, 21. Februar 2012 23:29
  • ...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.

    1. Passagierflüge-Schmalrumpf (z.B. 737)
    2. Passagierflüge-Großraum (z.B. A380)
    3. Frachtflüge
    4. 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:

    1. Kennbuchstabe
    2. Flugzeug
    3. 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:

    1. 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)
    2. 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
    3. Ich hinterlege Kennung "F" und Flugzeug "321" und Version "P8" für Kategorie 3.
    4. Die gleiche Kennung "F" und das gleiche Flugzeug "321" ohne Versionsangabe ist aber nun für die Kategorie 1 vorgesehen.
    5. Damit uns nicht zu langweilig wird, müssen wir Kennung "J" und ebenfalls "321" ohne Version wiederum für Kategorie 1 hinterlegen.
    6. 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

    Mittwoch, 22. Februar 2012 03:54
  • 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
    Donnerstag, 23. Februar 2012 10:40
  • 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

    Donnerstag, 23. Februar 2012 16:23
  • 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

    Samstag, 25. Februar 2012 18:06
  • 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

    Donnerstag, 1. März 2012 23:50