Database
 sql >> Datenbank >  >> RDS >> Database

5 unkomplizierte Tipps zur Verwendung der SQL UPDATE-Anweisung mit JOIN

"Hoppla! Mein Fehler." Wie oft haben Sie das gesagt, nachdem ein SQL-UPDATE schief gelaufen war? Die Sache ist die, wenn Sie nicht aufpassen, kann eine Tabellenaktualisierung schwerwiegende Folgen in Form der DELETE-Anweisung haben. Es könnte noch schlimmer werden, wenn Sie es verkomplizieren, indem Sie UPDATE mit JOIN verwenden. Deshalb müssen Sie darüber nachdenken, bevor Sie auf Ausführen klicken oder STRG-E drücken.

Heute lernen Sie also, wie Sie Ihr SQL-UPDATE problemlos mit JOIN codieren und niemals „Oops! Meine schlechte“ noch einmal.

Aber bevor wir zum Üben kommen, beginnen wir mit der Syntax. Außerdem werden sich unsere Neulinge bei SQL Server UPDATE mit JOIN wie zu Hause fühlen. Dann bereiten wir einige Daten und einige Beispiele vor. Sehen Sie sich schließlich die Sicherheitstipps an.

[sendpulse-form id=”12968″]

SQL JOIN-Syntax aktualisieren

UPDATE table1
SET column1 = <expression1 | value1> [, column2 = <expression2 | value2>, <columnN = expression3 | value3>]
FROM table1
[INNER | OUTER LEFT | OUTER RIGHT] JOIN table2 on table1.keycolumn = table2.keycolumn
[WHERE condition]

Daraus müssen wir einige Punkte herausarbeiten.

  1. Wir können jeweils eine Tabelle für mindestens 1 Spalte oder einige wenige Spalten aktualisieren.
  2. Wir brauchen die FROM-Klausel, um einen JOIN hinzuzufügen. Das Objekt in der FROM-Klausel kann mit dem zu aktualisierenden Objekt identisch sein oder nicht.
  3. Wir können entweder INNER oder OUTER JOIN verwenden (siehe Beispiele später).
  4. Wir können nur eine Teilmenge der Daten mit der WHERE-Klausel aktualisieren.

Bevor wir unsere Beispiele haben, bereiten wir die Daten vor.

Unsere Testdaten

Lassen Sie uns aus Liebe zu Filmen eine Datenbank mit Filmtiteln mit Benutzerbewertungen erstellen.

CREATE DATABASE [Movies]
GO

USE [Movies]
GO

CREATE TABLE [dbo].[Titles](
	[TitleID] [int] IDENTITY(1,1) NOT NULL,
	[Title] [varchar](50) NOT NULL,
	[ReleaseDate] [date] NOT NULL,
	[OverallUserRating] [varchar](10) NULL,
 CONSTRAINT [PK_Titles] PRIMARY KEY CLUSTERED 
(
	[TitleID] ASC
))
GO

CREATE TABLE [dbo].[UserRatings](
	[UserRatingID] [int] IDENTITY(1,1) NOT NULL,
	[TitleID] [int] NOT NULL,
	[User] [varchar](50) NOT NULL,
	[Rating] [tinyint] NOT NULL,
 CONSTRAINT [PK_UserRatings] PRIMARY KEY CLUSTERED 
(
	[UserRatingID] ASC
))
GO

ALTER TABLE [dbo].[UserRatings]  WITH CHECK ADD  CONSTRAINT [FK_UserRatings_Titles] FOREIGN KEY([TitleID])
REFERENCES [dbo].[Titles] ([TitleID])
GO

ALTER TABLE [dbo].[UserRatings] CHECK CONSTRAINT [FK_UserRatings_Titles]
GO

ALTER TABLE [dbo].[UserRatings]  WITH CHECK ADD  CONSTRAINT [CK_UserRatings_Rating] CHECK  (([Rating]>=(1) AND [Rating]<=(5)))
GO

ALTER TABLE [dbo].[UserRatings] CHECK CONSTRAINT [CK_UserRatings_Rating]
GO

Nachdem wir nun die Datenbank und die Tabellen haben, fügen wir einige Daten ein:

INSERT INTO Titles
(Title, ReleaseDate)
VALUES 
('The Avengers', '05/04/2012'),
('Avengers: Age of Ultron','5/1/2015'),
('Avengers: Infinity War','4/27/2018'),
('Avengers: Endgame','4/26/2019'),
('Captain America: Civil War','5/6/2016')
GO

INSERT INTO UserRatings(TitleID, [User], Rating) 
VALUES 
(1,'Natasha',5),
(1,'Bruce',3),
(1,'Tony',4),
(1,'Bucky',5),
(2,'Steve',4),
(2,'Wanda',3),
(2,'Pietro',2),
(2,'Clint',5),
(3,'Hope',5),
(3,'Sam',5),
(3,'Nick',3),
(3,'James',5),
(4,'Scott',5),
(4,'Wong',5),
(4,'Peter',5),
(4,'Carol',4),
(4,'Shuri',5)
GO

SQL Server-UPDATE mit MITGLIED Beispiel

Wir werden verschiedene Beispiele untersuchen, die das gleiche Ziel haben, das OverallUserRating zu aktualisieren in den Titeln Tisch. Bewertungen können zwischen 1 und 5 liegen. Gesamtnutzerbewertung ist der Durchschnitt aller Bewertungen für einen Filmtitel.

Hier ist der Ausgangszustand der Tabelle:

Beispiel für UPDATE LEFT JOIN

-- SQL UPDATE with LEFT OUTER JOIN
SELECT
 a.TitleID
,CAST(CAST(AVG(CAST(b.Rating AS DECIMAL(3,2))) AS DECIMAL(3,2)) AS varchar(9)) AS AverageRating
INTO #ComputedRatings
FROM titles a
INNER JOIN UserRatings b ON a.TitleID = b.TitleID
GROUP BY a.TitleID

-- mark 'No Rating' if there are no existing ratings
UPDATE Titles
SET OverallUserRating = ISNULL(b.AverageRating,'No Rating') 
FROM Titles a
LEFT JOIN #ComputedRatings b ON a.TitleID = b.TitleID

Die erste SELECT-Anweisung berechnet die durchschnittliche Bewertung pro Filmtitel basierend auf den UserRatings Tisch. Das Ergebnis wird in eine temporäre Tabelle namens #ComputedRatings ausgegeben . Da wir INNER JOIN verwenden, werden die Filmtitel ohne Bewertungen verworfen.

In der UPDATE-Anweisung werden die Titles Tabelle wurde mit einem LEFT JOIN von #ComputedRatings aktualisiert temporäre Tabelle. Wenn die durchschnittliche Bewertung Null ist , wird der Wert zu Keine Bewertung . In unserem Beispiel Captain America:Civil War hat noch keine Benutzerbewertungen – siehe Abbildung 2.

Beispiel für SQL UPDATE INNER JOIN

So geht's:

-- SQL UPDATE with INNER JOIN
SELECT
 a.TitleID
,ISNULL(CAST(CAST(AVG(CAST(b.Rating AS DECIMAL(3,2))) AS DECIMAL(3,2)) AS varchar(9)),'No Rating')  AS AverageRating
INTO #ComputedRatings
FROM titles a
LEFT JOIN UserRatings b ON a.TitleID = b.TitleID
GROUP BY a.TitleID


UPDATE Titles
SET OverallUserRating = b.AverageRating
FROM Titles a
INNER JOIN #ComputedRatings b ON a.TitleID = b.TitleID

Wenn Sie den obigen Code ausführen, ist das Ergebnis dasselbe wie in Abbildung 2. Aber was ist der Unterschied zwischen den beiden Codes?

  • Die erste SELECT-Anweisung berücksichtigt im Gegensatz zu unserem LEFT JOIN-Beispiel zuvor die NULL-Benutzerbewertung. Es verwirft den Filmtitel nicht ohne Benutzerbewertungen. Diesmal also Keine Bewertung Wert für Captain America:Civil War wird bereits berücksichtigt.
  • Ein INNER JOIN mit der direkten Zuweisung des AverageRating Wert ist besser geeignet, da alle TitleIDs verrechnet werden.

Statt einer temporären Tabelle kann nun auch ein Common Table Expression (CTE) verwendet werden. Hier ist der geänderte Code:

-- SQL UPDATE with JOIN using INNER JOIN from a CTE
;WITH ComputedRatings AS
(SELECT
 a.TitleID
,ISNULL(CAST(CAST(AVG(CAST(b.Rating AS DECIMAL(3,2))) AS DECIMAL(3,2)) AS varchar(9)),'No Rating')  AS AverageRating
FROM Titles a
LEFT JOIN UserRatings b ON a.TitleID = b.TitleID
GROUP BY a.TitleID)
UPDATE Titles
SET OverallUserRating = b.AverageRating
FROM Titles t
INNER JOIN ComputedRatings cr ON t.TitleID = cr.TitleID

Weitere Informationen

  • Ihr ultimativer Leitfaden für SQL JOIN:INNER JOIN – Teil 1
  • Ihr ultimativer Leitfaden für SQL JOIN:OUTER JOIN – Teil 2

Update verwenden Befehl mit Beitreten Sicher (5 Tipps)

Sicherheit bezieht sich auf die Aktualisierung beabsichtigter Aufzeichnungen. Außerdem geht es darum, die Aufzeichnungen, die wir nicht zu aktualisieren beabsichtigen, NICHT anzufassen. Hier behandeln wir 5 Szenarien:

Sehen Sie sich zuerst die Datensätze mit der SELECT-Anweisung an

Dieser Tipp ist perfekt für ein paar Schallplatten. Bevor Sie also die Datensätze aktualisieren, versuchen Sie Folgendes:

Das ist ganz einfach. Und wenn es gut aussieht, kommentieren Sie die UPDATE- und SET-Klauseln aus. Markieren Sie die SELECT-Klausel als Kommentar. Dann können Sie loslegen. Auf diese Weise minimieren Sie die Schadenskontrolle, weil Sie proaktiv sind.

Führen Sie einen Testlauf mit temporären Tabellen durch

Sie sind unsicher, ob ein Fehler auftreten könnte? Versuchen Sie dann, die Tabellendatensätze, die Sie aktualisieren möchten, in eine temporäre Tabelle zu kopieren. Führen Sie danach einen Probelauf von dort aus durch.

Gibt es keine Laufzeitfehler? Sehen die Ergebnisse gut aus? Ersetzen Sie dann die temporäre Tabelle durch die ursprüngliche Tabelle. Auf diese Weise wissen Sie, dass es unterwegs keine Laufzeitfehler geben wird.

Beachten Sie auch, dass temporäre Tabellen eine der Möglichkeiten zum Speichern der Kopien von Originaltabellen sind. Sie können auch speicheroptimierte Tabellen oder eine Datenbanksicherung verwenden. Mit den Datenbank-Backups haben Sie mehr Freiheit, mit Datensätzen zu spielen, die Sie aktualisieren müssen. Aber der Nachteil davon ist Speicherplatz.

Weitere Informationen

  • CREATE TABLE (Transact-SQL) – Temporäre Tabellen

Versuchen Sie, die OUTPUT-Klausel in UPDATE hinzuzufügen

Möchten Sie die Zeit zurückdrehen, bevor Sie das Update ausführen? Wenn Sie so skeptisch sind, können Sie die OUTPUT-Klausel verwenden und Vergangenheit und Gegenwart anzeigen. Im folgenden Beispiel dient eine Tabellenvariable dazu, die vorherigen und aktuellen Werte nach dem Update zu sichern. Sie können dann die Tabellenvariable AUSWÄHLEN, um die Ergebnisse anzuzeigen:

DECLARE @tvTitles AS TABLE(TitleID INT NOT NULL,
                           OldOverallRatings VARCHAR(10) NULL,
			    NewOverAllRatings varchar(10) NOT NULL)

;WITH ComputedRatings AS
(
	SELECT
	a.TitleID
	,ISNULL(CAST(CAST(AVG(CAST(b.Rating AS DECIMAL(3,2))) AS DECIMAL(3,2)) AS varchar(9)),'No Rating')  AS AverageRating
	FROM titles a
	LEFT JOIN UserRatings b ON a.TitleID = b.TitleID
	GROUP BY a.TitleID
)
UPDATE #tmpTitles
SET OverallUserRating = cr.AverageRating
OUTPUT INSERTED.TitleID, DELETED.OverallUserRating, INSERTED.OverallUserRating
INTO @tvTitles
FROM #tmpTitles t
INNER JOIN ComputedRatings cr ON t.TitleID = cr.TitleID

Einige Hinweise zu diesem Code:

  • Die Tabellenvariable fungiert als Container der vorherigen und aktuellen Werte.
  • Das übliche Update mit CTE ist in Ordnung. Wir verwenden immer noch die temporäre Tabelle, um auf Nummer sicher zu gehen.
  • Die OUTPUT-Klausel gilt, um die vorherigen und aktuellen Werte in die Tabellenvariable auszugeben. INSERTED enthält neue Werte, während DELETED alte Werte enthält.

Wenn Sie ein SELECT von der Tabellenvariablen ausgeben, können Sie Folgendes erwarten:

Das Ergebnis ist wie Abbildung 3, aber es blickt in die Zukunft. Dieser blickt in die Vergangenheit. Wenn es anders ist, ist zwischendurch etwas schief gelaufen.

Die gute Nachricht ist, dass Sie alte Werte in der Tabellenvariablen verwenden können, um den vorherigen Zustand wiederherzustellen. Aber wenn es dasselbe ist, dann bist du wieder gut zu gehen. Sie können die OUTPUT-Klausel als Kommentar markieren oder entfernen und dann die temporäre Tabelle durch die ursprüngliche Tabelle ersetzen.

Weitere Informationen

  • OUTPUT-Klausel (Transact-SQL)

Verwenden Sie TRY…CATCH, um zukünftige Fehler zu behandeln

Die vorherigen 3 Tipps sind hilfreich, wenn Sie Ihren Code erstellen und dann testen. Aber wir alle wissen, dass wir nicht alles vorhersehen können. Daher müssen wir dem Code weitere Sicherheitsnetze hinzufügen.

Apropos Sicherheitsnetze, T-SQL hat die TRY…CATCH-Fehlerbehandlungsblöcke wie C# und C++.

Schauen wir uns den modifizierten Code aus dem vorherigen Beispiel an:

BEGIN TRY						  
  ;WITH ComputedRatings AS
  (
    SELECT
     a.TitleID
    ,ISNULL(CAST(CAST(AVG(CAST(b.Rating AS DECIMAL(3,2))) AS DECIMAL(3,2)) AS varchar(20)),
            'No User Ratings Yet') AS AverageRating
    FROM titles a
    LEFT JOIN UserRatings b ON a.TitleID = b.TitleID
    GROUP BY a.TitleID
  )
  UPDATE Titles
  SET OverallUserRating = cr.AverageRating
  FROM Titles t
  INNER JOIN ComputedRatings cr ON t.TitleID = cr.TitleID

END TRY
BEGIN CATCH
 SELECT  
  ERROR_NUMBER() AS ErrorNumber  
 ,ERROR_SEVERITY() AS ErrorSeverity  
 ,ERROR_STATE() AS ErrorState  
 ,ERROR_PROCEDURE() AS ErrorProcedure  
 ,ERROR_LINE() AS ErrorLine  
 ,ERROR_MESSAGE() AS ErrorMessage;  

END CATCH

Ich habe den obigen Code geändert, um den Fehler beim Abschneiden der Zeichenfolge zu erzwingen. Die Gesamtnutzerbewertung Spalte in den Titeln Die Tabelle kann nur bis zu 10 Zeichen aufnehmen. Im CTE haben wir es auf 20 Zeichen geändert. Das wird nicht passen. Der CATCH-Block übernimmt den Moment des Auftretens des Fehlers und liefert die Fehlerinformationen.

Hier ist das Ergebnis:

Wir haben den Fehler ausgelöst. Wenn Sie unvorhergesehene Fehler während der Laufzeit abfangen müssen, ist dies eine Möglichkeit, damit umzugehen.

Weitere Informationen

  • VERSUCHEN…CATCH (Transact-SQL)

Transaktionsabwicklung verwenden

Endlich Transaktionen. Es stellt sicher, dass alles in den vorherigen Zustand zurückversetzt wird, bevor der Fehler auftrat, einschließlich UPDATE mit JOIN und allen anderen DML-Anweisungen. Dies ist eine gute Ergänzung zu Tipp Nr. 4 oben.

Lassen Sie uns den Code erneut ändern, um Transaktionen einzuschließen:

BEGIN TRANSACTION

BEGIN TRY						  
  ;WITH ComputedRatings AS
  (
    SELECT
     a.TitleID
    ,ISNULL(CAST(CAST(AVG(CAST(b.Rating AS DECIMAL(3,2))) AS DECIMAL(3,2)) AS varchar(20)),
            'No User Ratings Yet') AS AverageRating
    FROM titles a
    LEFT JOIN UserRatings b ON a.TitleID = b.TitleID
    GROUP BY a.TitleID
  )
  UPDATE Titles
  SET OverallUserRating = cr.AverageRating
  FROM Titles t
  INNER JOIN ComputedRatings cr ON t.TitleID = cr.TitleID

  COMMIT TRANSACTION
END TRY
BEGIN CATCH
 SELECT  
  ERROR_NUMBER() AS ErrorNumber  
 ,ERROR_SEVERITY() AS ErrorSeverity  
 ,ERROR_STATE() AS ErrorState  
 ,ERROR_PROCEDURE() AS ErrorProcedure  
 ,ERROR_LINE() AS ErrorLine  
 ,ERROR_MESSAGE() AS ErrorMessage;  

 ROLLBACK TRANSACTION
END CATCH

Es ist dasselbe wie im vorherigen Beispiel, mit Ausnahme von Transaktionen. Daher wird ein Fehler beim Abschneiden der Zeichenfolge erzwungen. Es wird nicht über COMMIT TRANSACTION hinausgehen, sondern im CATCH-Block mit ROLLBACK TRANSACTION, um die Werte auf ihre vorherigen Zustände zurückzusetzen.

Dies ist der Weg, wenn wir mit Updates, Einfügungen und Löschungen auf Nummer sicher gehen wollen.

Hinweis :Mit dem Query Builder-Feature von dbForge Studio for SQL Server können Sie jede Abfrage visuell in einem Diagramm entwerfen.

Weitere Informationen

  • Best Practices für T-SQL
  • So schreiben Sie T-SQL-Abfragen wie ein Profi

Schlussfolgerung

Sie haben die Syntax von SQL UPDATE mit JOIN gesehen. Beispiele und 5 unkomplizierte Tipps haben Sie weiter aufgeklärt. Die Anforderungen können sich von den Beispielen unterscheiden, aber Sie haben es verstanden. Sie können immer noch Fehler machen. Es ist jedoch möglich, sie auf nahezu Null zu reduzieren.

Warum wenden Sie diese Ideen nicht auf Ihre Situation an?

Wenn dieser Beitrag hilfreich war, können Sie ihn gerne auf Ihren bevorzugten Social-Media-Plattformen verbreiten. Und wenn Sie ein paar tolle Ideen hinzufügen möchten, sind Sie im Kommentarbereich herzlich willkommen.