Laden...

SQL - Selektion von Mengen aus 2 (fast) identischen Tabellen

Letzter Beitrag vor einem Jahr 7 Posts 838 Views
SQL - Selektion von Mengen aus 2 (fast) identischen Tabellen

Verwendetes Datenbanksystem: Microsoft SQL Server 2017

Die Lösung die Benötigt wird, ist folgende:


Table1
- Fields: Id (Key), Nr (Key), Field1, Field2

Table2
- Fields: Id (Key), Nr (Key), Field1, Field2, Field3

Daten1
0, 10, Text1, Text2
1, 11, Text1, Text2
2, 12, Text1, Text2

Daten2
1, 11, Text1 edit, Text2 edit, Text3

Es müssen immer die Daten aus beiden Tabellen selektiert werden. Es sollen mit Priorität, wenn mit denselben Schlüssel in Daten2 ein Satz vorkommt, auch dieser verwendet und der aus Daten1 ignoriert werden.

Also das Ergebnis sollte dann so aussehen:

0, 10, Text1,      Text2,      ''
1, 11, Text1 edit, Text2 edit, Text3
2, 12, Text1,      Text2,      ''

Meine derzeitige Selektion sieht so aus:

SELECT m.Id, m.Nr, m.Field1, m.Field2, m.Field3
(
    SELECT a.Id, a.Nr, a.Field1, a.Field2, CAST('' AS NVARCHAR(256)) as Field3
    FROM Table1 a
    LEFT JOIN Table2 b
    ON a.Id=b.Id
    WHERE b.Id IS NULL
    
    UNION ALL
    
    SELECT Id, Nr, Field1, Field2, Field3
    FROM Table2
) m

Table2 ist eine Tabelle, in der nur Datensätze vorhanden sind, die gerade bearbeitet werden. Daher man diese Änderungen zurücksetzen kann, ist diese Vorgehensweise notwendig. (vielleicht gibt es von der grundsätzlichen Idee her eine bessere Lösung?)

Table1 sollte vom aktuellen Stand nicht geändert werden, da es sonst zu breaking changes kommt, die eine menge Anpassungen rund um den Server fordern würde.

Mit diesen süßen kleinen Beispiel sieht es nicht so arg aus, bei größeren Tabellen wird es dann schon sehr unübersichtlich.

Zudem können noch weitere WHERE bzw. JOIN Klauseln hinzukommen, die das UNION nochmals filtern werden. (Auch  TOP, ORDER BY, OFFSET...) Innerhalb des UNION sollte sich nichts mehr ändern.

Meine eigentliche Frage ist die, ob die Art der Selektion auf diese Weise annehmbar ist oder es eine bessere Lösung gibt?

SG Thomas

Ich habe den Titel mal angepasst, so dass Suchende auch etwas damit anfangen können. EDIT: Ich sollte beim Wort "Shift" im Titel das "f" nicht vergessen... 😄

Oder wäre diese Lösung besser:

SELECT a.Id,     a.Nr,     a.Field1,     a.Field2, 
       b.IdEdit IS NOT NULL AS HasEditLine, 
       b.IdEdit, b.NrEdit, b.Field1Edit, b.Field2Edit, b.Field3Edit -- Wenn in Table2 die Namen mit dem Suffix Edit ergänzt werden
FROM Table1 AS a
LEFT JOIN Table2Edit AS b 
       ON a.Id=b.IdEdit

Im Code müsste das Model erweitert werden, sodass alle Daten vorhanden sein können.

In dem Fall müsste man im Code entsprechend darauf reagieren.

Sollte von der Performance her wesentlich besser werden oder?

Auch wenn ich das jetzt nicht unbedingt schön finde...

Ich habe den Titel mal angepasst, so dass Suchende auch etwas damit anfangen können. EDIT: Ich sollte beim Wort "Shift" im Titel das "f" nicht vergessen... 😄

Pauschal wirst du vermutlich keine passende bzw. die beste Antwort kriegen.
Du musst hier selbst prüfen welcher Ansatz das passende Ergebnis liefert.
Wenn du die Daten aus zwei Tabellen zusammenführen musst, wäre der UNION ALL Ansatz schon eine möglichkeit.

Ansonsten könntest du, wie in deinem zweiten Ansatz, die Daten per Join ermitteln und dann selbst Dedublizieren.
Dann brauchst du ggf. mehr Code um die Daten passend für dein Ergebnis aufzubereiten, dies kann u.U. aber auch besser sein.
Was der beste Ansatz ist musst du selbst prüfen/messen, da können wir dir nicht wirklich helfen.
Da spielen auch viele Faktoren eine Rolle wie z.B. Aufbau der Tabellen, Indexe usw.
Was für dich dann vertretbar ist und auch das korrekte Ergebnis liefert, musst du dann im Endeffekt selbst prüfen.

T-Virus

Developer, Developer, Developer, Developer....

99 little bugs in the code, 99 little bugs. Take one down, patch it around, 117 little bugs in the code.

Hallo T-Virus,

danke für deine Antwort.

Du hast ja recht das das ganz von der Situation ankommt. Generell wäre die 2. Lösung denk ich von der DB-Performance her besser als die Erste..

Indexe gibt es generell auf alle Primary-Keys, sonst nicht. Dennoch wird auch mit like gesucht (ist indirekt konfigurierbar), sowie extra gejoint usw. zudem sind die DB Tabellen in der Regel viel größer. Die erste Variante bläst die Kommandos ziemlich stark auf und es wird doch unübersichtlicher.

Die Zweite die Models.. wäre aber denk ich wesentlich überscihtlicher, auch wenn es nicht schön ist.

Ich habe den Titel mal angepasst, so dass Suchende auch etwas damit anfangen können. EDIT: Ich sollte beim Wort "Shift" im Titel das "f" nicht vergessen... 😄

Zitat von ThomasE.

Indexe gibt es generell auf alle Primary-Keys, sonst nicht.

Das halt generell nicht so dolle.. Indexe sollten so gesetzt sein, dass diese unterstützend zur Anfrage wirken.
Ausnahme wäre, wenn Du eine Datenbank hast, die auf Schreiben optimiert ist und nicht auf Lesen.

Wenn Du eine auf Lesen optimierte DB willst, dann solltest Du so eine Problemstellung ohnehin mit indizierten Views umsetzen.
Ansonsten wirst Du sehr wahrscheinlich immer das Problem des Full Index Scans haben und damit immer langsamer werden, je mehr Daten vorhanden sind.

@Abt
Meinst du nicht einen Full Table Scan?

Ansonsten brauchst du passende Indexe um die Daten optimal zu laden.
Gerade wenn die Datenmenge groß ist, spielt ein Index eine wichtige Rolle.
Natürlich sollte dieser zusammen mit der Abfrage passen.
Im Idealfall kannst du auch einen Index bauen, der dir alle Daten liefert.
Dadurch muss die Tabelle nicht angefasst werden, was aber nicht immer möglich ist.
Je komplexer die Abfragen werden und umso mehr Spalten/Tabellen bei der Abfrage dazu kommmen umso schwerer wird es hier nur mit Indexen zu arbeiten.

Alternativ wären auch materialisierte Views was, wenn sich die Daten selten ändern.
Dann musst du die View nur aktualisieren, wenn sich die Daten ändern.
Hier musst du aber prüfen was in Kombination mit deiner Anforderung am besten läuft.

T-Virus

Developer, Developer, Developer, Developer....

99 little bugs in the code, 99 little bugs. Take one down, patch it around, 117 little bugs in the code.

Neben den bereits schon angesprochenen Indizes, würde ich mich für Variante 2 entscheiden, diese aber wie folgt anpassen (damit keine Codeanpassungen notwendig sind):

SELECT 
a.Id, 
CASE WHEN b.Id IS NULL THEN a.Nr ELSE b.Nr END as Nr,
CASE WHEN b.Id IS NULL THEN a.Field1 ELSE b.Field1 END as Field1,
...
FROM Table1 AS a
LEFT JOIN Table2Edit AS b ON a.Id=b.Id

Du brauchst die Tabelle 2 nicht anfassen (keine Suffixe) und der lesende Code muss ebenfalls nicht angepasst werden. Hast Du hier Indizes für a.Id und b.IdEdit, ist diese Variante recht fix...