Right Join vs Left Join - Meine Joins sind unterbrochen und ich verstehe nicht warum


7

http://sqlfiddle.com/#!3/ef71e/1

Ich habe die Geige ziemlich drastisch reduziert, aber ich denke, die Absicht scheint durch. [Def]ist eine [DefaultClassification]Tabelle und [Cls]eine [Classification]Tabelle mit einigen alten Datensätzen, die hinzugefügt werden müssen. Die DefaultClassification-Tabelle wird in Zukunft verwendet, um neue Gruppen von Datensätzen in einer weiteren Tabelle zu erzeugen, und wir "brechen" ein vorhandenes Bit auf von Logik / Daten mit diesem Prozess.

Ich habe mein Bestes getan, um das Ganze auf das Wesentliche zu reduzieren, aber ich habe einen ähnlichen Prozess, der direkt nach diesem ausgeführt wird. Daher möchte ich bewährte Methoden kennenlernen und herausfinden, warum diese Abfrage fehlerhaft ist.

Als ich dies schrieb, wollte ich, dass es in einer Umgebung ab 2008 ausgeführt wird, skriptgesteuert oder manuell in SSMS. Ich weiß nicht, dass es kein Skript gibt, aber es könnte sein. Im Moment wird es komplett von Hand betrieben. Das Rollback und die Auswahl oben über den Drucknachrichten am Ende sind darauf zurückzuführen, dass es nicht richtig funktioniert. Daher kann ich es vor dem Festschreiben überprüfen. Ich würde jedoch ein gültiges Skript bevorzugen, mit dem ich mich nicht herumschlagen muss

Das spezifische Problem, das ich habe, befindet sich in Zeile 62 dieses Revisions-1-Links http://sqlfiddle.com/#!3/ef71e/1 und es sieht folgendermaßen aus:

RECHTE AUSSENVERBINDUNG [Def] tcd

Wenn ich das RECHTS nach LINKS drehe, wird die Einfügung ausgeführt, es werden jedoch keine Duplikate erkannt (um das Einfügen zu verhindern). Wenn ich das RECHTE mache, werden Duplikate erkannt, aber keine Einfügungen verarbeitet.

Was habe ich gebrochen? Und warum?


Und mir wurde gesagt, dass die Verwendung des @@ERRORJuju schlecht war, aber ich weiß nicht warum, also Bonuspunkte (ein Kopfgeld von 100 Wiederholungen) auch für diese Erklärung.

Antworten:


11

Warum ist @@ ERROR schlecht juju?

In SQL Server 2005 macht die Verwendung von @@ ERROR das Leben schwieriger als nötig, um Fehler zu erkennen und abzufangen.

1) Sie müssen nach jeder Aussage testen . Nur aus Wartungssicht wird mein Hund die Schutzbrille nichts tun, um Sie zu schützen. Sie können auch argumentieren, dass die gesamte Logik zum Kopieren / Einfügen für die Fehlerbehandlung den "wahren" Zweck Ihres Codes verdeckt.

2) @@ ERROR ist zu flüchtig. Im folgenden Code löst Zeile 2 den Fehler 8134 aus. Zeile 3 Ich wähle den Wert aus und 8134 wird verbraucht. Warum? Weil die SELECT-Anweisung keinen Fehler ausgelöst hat. Selbst wenn dies der Fall gewesen wäre, wäre es ein anderer Fehler gewesen als der, der fehlgeschlagen wäre.

DECLARE @ErrorCode int
SELECT 1/0 AS div_zero
SELECT @@error AS [@@error]
SET @errorCode = @@error
SELECT @errorCode AS errorCode

3) Selbst wenn Sie mit dem @@ ERROR mit den obigen 2 gut umgehen, besteht meine Herausforderung darin, dass der Fehler zumindest in SSMS immer noch "durchkommt". Führen Sie die erste Hälfte der Abfrage aus, und obwohl ich den Fehler logisch behandelt habe, sickert er dennoch zum Anrufer zurück.

SET NOCOUNT ON

DECLARE @ErrorCode int;
SELECT 1/0 AS div_zero;
SET @errorCode = @@error;
IF @ErrorCode <> 0
BEGIN
    -- I did something here to handle the error
    -- SSMS still reports that the Query completed with errors
    print 'developer electrocuted';
END
GO

Vergleichen Sie das mit

-- error handled *and* query executes successfully
BEGIN TRY
    -- This will report query executed successfully
     SELECT 1/0 AS handled_div_zero;
END TRY
BEGIN CATCH
SELECT
    ERROR_NUMBER()AS error_number --returns the number of the error.
,   ERROR_SEVERITY() AS error_severity --returns the severity.
,   ERROR_STATE()AS error_state  --returns the error state number.
,   ERROR_PROCEDURE() AS error_procedure --returns the name of the stored procedure or trigger where the error occurred.
,   ERROR_LINE() AS error_line --returns the line number inside the routine that caused the error.
,   ERROR_MESSAGE() AS error_message; --returns the complete text of the error message. The text includes the values supplied for any substitutable parameters, such as lengths, object names, or times.
END CATCH

SQL Server 2012 beendet das, was 2005 gestartet wurde, und bietet Folgendes: Auf THROWdiese Weise können Sie Ihren Fehler in Ihrem CATCHBlock behandeln. Anstatt Ihren Aufrufstapel zu zerschlagen, können Sie denselben Fehler jetzt wieder an den Aufrufer weiterleiten. Andernfalls müssen Sie jedes Mal, wenn Sie versuchen, eine Ebene im Aufrufstapel zu reparieren, einen Fehler auslösen.


In fast allen Fällen, in denen ich gesehen habe, dass Leute @@ error verwenden, haben sie es versäumt, nach jedem einzelnen Code zu testen, und die Person fragt sich, warum die Fehler den Prozess nicht stoppen. Ich lehne es ab, eine Codeüberprüfung zu bestehen, wenn sie einen @ @ -Fehler enthält.
HLGEM

2

Ok, ich schrieb einen Artikel über SQL Server - Zentral hier , dass Sie mit der linken / rechten äußeren Fragen verbinden helfen können. Wenn Sie jedoch in diesem Fall versuchen, Duplikate zu entfernen, denke ich, dass das, wonach Sie suchen, NICHT vorhanden ist.

SELECT 
      tTCD.ClsID
    , tTCD.ParID
    , tTCD.Name
    , tTCD.IsExpense
    , tTCD.CD
FROM @Default tTCD
WHERE NOT EXISTS (
        SELECT 1 FROM [Def] tcd
            WHERE  tcd.ClsID = tTCD.ClsID
            AND tcd.Name = tTCD.Name
            AND tcd.IsExpense = tTCD.IsExpense)
AND tTCD.IsExpense IS NOT NULL

Ihr vorhandener Code, der RIGHT OUTER JOIN verwendet, enthält eine WHERE-Klausel in der Tabelle LEFT. Da Sie NULL-Werte ausschließen und immer dann, wenn es keine Übereinstimmung gibt, einen RECHTEN AUSSEN-JOIN erhalten, erhalten Sie einen NULL-Wert für die Tabelle LINKS. Die Verwendung von NOT EXISTS sollte mehr helfen. Ihre Testdaten enthalten jedoch keine Duplikate, sodass es schwer zu sagen ist.


Ja, das ist eine Diskussion, die wir im Chatroom geführt haben. Es gibt nur ungefähr ein Dutzend Dupes, aber ich kann keine davon haben, wenn dieser Prozess ausgeführt wird.
Jcolebrand

1

Sie können nicht einfach die rechten und linken Verknüpfungen tauschen. Sie bedeuten zwei verschiedene Dinge. Sie müssen auch verstehen, wie sich eine where-Bedingung auf der Tabelle auf der linken Seite eines rechten Joins oder auf der rechten Seite eines linken Joins auswirkt. Unter diesem Link erfahren Sie, warum sich der Join in einen inneren Join ändert. http://wiki.lessthandot.com/index.php/WHERE_conditions_on_a_LEFT_JOIN

Überprüfen Sie, ob dieser Code Ihren Wünschen entspricht:

 SELECT 
          tTCD.ClsID
        , tTCD.ParID
        , tTCD.Name
        , tTCD.IsExpense
        , tTCD.CD
   FROM  [Def] tcd
   LEFT OUTER JOIN @Default tTCD
        ON  tcd.ClsID = tTCD.ClsID
        AND tcd.Name = tTCD.Name
        AND tcd.IsExpense = tTCD.IsExpense
        AND tTCD.IsExpense IS NOT NULL

Für die Zukunft ist es im Allgemeinen am besten, nur linke Verknüpfungen zu verwenden.

Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.