"Ups! Min fejl." Hvor mange gange sagde du dette, efter at en SQL-OPDATERING var gået galt? Sagen er, at hvis du ikke er forsigtig, kan en tabelopdatering have alvorlige konsekvenser i form af DELETE-erklæringen. Det kan blive endnu værre, hvis du komplicerer det ved at bruge UPDATE med JOIN. Det er derfor, du skal tænke dig om, før du trykker på Udfør eller trykker på CTRL-E.
Så i dag vil du lære at kode din SQL-OPDATERING med JOIN uden besvær og aldrig sige "Ups! My bad” igen.
Men inden vi kommer til at øve, starter vi med syntaksen. Det vil også få vores nybegyndere til at føle sig hjemme omkring SQL Server UPDATE med JOIN. Derefter vil vi udarbejde nogle data og et par eksempler. Og endelig, undersøg sikkerhedstipsene.
[sendpulse-form id="12968″]
SQL OPDATERING JOIN-syntaks
OPDATERING tabel1SÆT kolonne1 = [, kolonne2 =, ]FRA tabel1[INDRE | YDER TIL VENSTRE | YDRE HØJRE] JOIN table2 on table1.keycolumn =table2.keycolumn[WHERE condition]
Vi er nødt til at specificere et par punkter fra dette.
- Vi kan opdatere én tabel ad gangen for mindst 1 kolonne eller nogle få kolonner.
- Vi har brug for FROM-sætningen for at tilføje en JOIN. Objektet i FROM-sætningen er muligvis det samme som det objekt, der opdateres.
- Vi kan bruge enten INNER eller YDER JOIN (se eksempler senere).
- Vi kan kun opdatere en delmængde af dataene ved hjælp af WHERE-sætningen.
Før vi har vores eksempler, lad os forberede dataene.
Vores testdata
For kærligheden til film, lad os oprette en database med filmtitler med brugervurderinger.
OPRET DATABASE [Film]GOUSE [Film]GOCREATE TABLE [dbo].[Titler]( [TitelID] [int] IDENTITET(1,1) IKKE NULL, [Titel] [varchar](50) IKKE NULL, [ReleaseDate] [dato] IKKE NULL, [OverallUserRating] [varchar](10) NULL, BEGRÆNSNING [PK_Titler] PRIMÆR NØGLE KLUSTERET ( [TitleID] ASC))GOCREATE TABEL [dbo].[UserRatings](] [UserRating] int] IDENTITET(1,1) IKKE NULL, [TitelID] [int] IKKE NULL, [Bruger] [varchar](50) IKKE NULL, [Rating] [tinyint] IKKE NULL, BEGRÆNSNING [PK_UserRatings] PRIMÆR NØGLE KLYNGET ( [ UserRatingID] ASC))GOALTER TABLE [dbo].[UserRatings] MED CHECK TILFØJ BEGRÆNSNING [FK_UserRatings_Titles] UDENLANDSKE KEY([TitleID])REFERENCER [dbo].[Titler] ([TitleID])GOALTER TABEL [dboating]. CHECK CONSTRAINT [FK_UserRatings_Titles]GOALTER-TABEL [dbo].[UserRatings] MED CHECK TILFØJ BEGRÆNSNING [CK_UserRatings_Rating] CHECK (([Rating]>=(1) OG [Rating]<=(5)))GOALTER-TABEL [dbo].[ UserRatings] CHECK CONSTRAINT [CK_UserRatings_Rating]GO
Nu hvor vi har databasen og tabellerne, lad os indsætte nogle data:
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')GOINSERT INTO Brugervurderinger(TitelID, [Bruger], Bedømmelse) VÆRDIER (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,'Håb',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 OPDATERING med DELTAG Eksempel
Vi vil undersøge forskellige eksempler med samme mål om at opdatere OverallUserRating i Titler bord. Bedømmelser kan være 1 til 5. OverallUserRating er gennemsnittet af alle vurderinger for en filmtitel.
Her er den indledende tilstand af tabellen:
OPDATERING VENSTRE JOIN Eksempel
-- SQL-OPDATERING med VENSTRE YDRE JOINSELECT a.TitleID,CAST(CAST(AVG(CAST(b.Rating AS DECIMAL(3,2))) AS DECIMAL(3,2)) AS varchar(9) )) SOM GennemsnitsbedømmelseINTO #ComputedRatingsFRA titler aINNER JOIN UserRatings b PÅ a.TitleID =b.TitleIDGROUP BY a.TitleID-- markér 'Ingen bedømmelse', hvis der ikke er nogen eksisterende bedømmelser. FRA Titler til VENSTRE JOIN #ComputedRatings b PÅ a.TitleID =b.TitleID
Den første SELECT-sætning beregner den gennemsnitlige vurdering pr. filmtitel baseret på UserRatings bord. Resultatet dumpes til en midlertidig tabel kaldet #ComputedRatings . Da vi bruger INNER JOIN, kasseres filmtitlerne uden vurderinger.
I UPDATE-sætningen er Titler tabellen blev opdateret ved hjælp af en LEFT JOIN fra #ComputedRatings midlertidigt bord. Hvis den gennemsnitlige bedømmelse er nul , bliver værdien Ingen bedømmelse . I vores eksempel, Captain America:Civil War har endnu ingen brugervurderinger – se figur 2.
SQL-OPDATERING INDRE JOIN-eksempel
Sådan går det:
-- SQL OPDATERING med INNER JOINSELECT a.TitleID,ISNULL(CAST(CAST(AVG(CAST(b.Rating AS DECIMAL(3,2))) AS DECIMAL(3,2)) AS varchar( 9)),'Ingen bedømmelse') AS AverageRatingINTO #ComputedRatingsFROM titler aLEFT JOIN UserRatings b ON a.TitleID =b.TitleIDGROUP BY a.TitleIDUPDATE TitlesSET OverallUserRating =b.AverageRatingFROM Titler aINNER JOINTitle aINNER JOINTitle aINNER JOINTitle a.Title a.Title a.Title
Når du kører ovenstående kode, vil resultatet være det samme som i figur 2. Men hvad er forskellen mellem de to koder?
- Den første SELECT-sætning betragter brugervurderingen NULL i modsætning til vores LEFT JOIN-eksempel tidligere. Den kasserer ikke filmtitlen uden brugervurderinger. Så denne gang, Ingen bedømmelse værdi for Captain America:Civil War overvejes allerede.
- En INNER JOIN med direkte tildeling af AverageRating værdi er mere passende, da alle TitleID'er er redegjort for.
Nu, i stedet for en midlertidig tabel, kan fælles tabeludtryk (CTE) også bruges. Her er den ændrede kode:
-- SQL OPDATERING med JOIN ved hjælp af INNER JOIN fra en CTE;WITH ComputedRatings AS(SELECT a.TitleID,ISNULL(CAST(CAST(AVG(CAST(b.Rating AS DECIMAL(3,2))) SOM DECIMAL(3,2)) SOM varchar(9)),'Ingen rating') AS AverageRatingFROM Titler aLEFT JOIN UserRatings b PÅ a.TitleID =b.TitleIDGROUP BY a.TitleID)UPDATE TitlesSET OverallUserRating =b.AverageRatingFROM Titler tINNER JOIN ComputedRatings cr ON t.TitleID =cr.TitleID
Flere oplysninger
- Din ultimative guide til SQL JOIN:INNER JOIN – Del 1
- Din ultimative guide til SQL JOIN:OUTER JOIN – Del 2
Brug af opdatering Kommando med Join Sikkert (5 tip)
Sikkerhed henviser til opdatering af tilsigtede registreringer. Det handler også om IKKE at røre ved de poster, vi ikke har til hensigt at opdatere. Her skal vi behandle 5 scenarier:
Se posterne først med SELECT-erklæringen
Dette tip er perfekt til et par plader. Så før du påvirker posterne for opdatering, prøv dette:
Det er nemt at gøre. Og hvis det ser godt ud, skal du fjerne kommentarer til UPDATE- og SET-klausulerne. Marker SELECT-sætningen som en kommentar. Så er du god til at gå. På denne måde minimerer du skadeskontrol, fordi du er proaktiv.
Foretag en prøvekørsel ved hjælp af midlertidige tabeller
Føler du dig usikker på, om der kan opstå en fejl? Prøv derefter at dumpe de tabelposter, du ønsker at opdatere, til en midlertidig tabel. Efter det, lav en prøvekørsel derfra.
Er der ingen runtime fejl? Ser resultaterne gode ud? Udskift derefter den midlertidige tabel med den originale tabel. På denne måde ved du, at der ikke vil være nogen runtime-fejl undervejs.
Bemærk også, at midlertidige tabeller er en af måderne at gemme kopierne af originale tabeller på. Du kan også bruge hukommelsesoptimerede tabeller eller en database backup. Med database-backuperne har du større frihed til at lege med de poster, du skal opdatere. Men ulempen ved dette er lagerplads.
Flere oplysninger
- OPRET TABEL (Transact-SQL) – Midlertidige tabeller
Prøv at tilføje OUTPUT-klausulen til OPDATERING
Vil du tilbage i tiden, før du kører opdateringen? Hvis du er så skeptisk, kan du bruge OUTPUT-klausulen og se fortiden og nutiden. I eksemplet nedenfor tjener en tabelvariabel til at dumpe de tidligere og nuværende værdier efter opdateringen. Du kan derefter VÆLGE tabelvariablen for at se resultaterne:
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 FRA titler a LEFT JOIN UserRatings b ON a.TitleID =b. TitleID GROUP BY a.TitleID)UPDATE #tmpTitlesSET OverallUserRating =cr.AverageRatingOUTPUT INSERTED.TitleID, DELETED.OverallUserRating, INSERTED.OverallUserRatingINTO @tvTitlesFROM #tmpTitler tINNER JOIN.
Et par punkter at bemærke om denne kode:
- Tabelvariablen fungerer som en beholder af de tidligere og nuværende værdier.
- Den sædvanlige opdatering med CTE er i orden. Vi bruger stadig det midlertidige bord til at spille sikkert.
- OUTPUT-udtrykket gælder for at dumpe de tidligere og nuværende værdier i tabelvariablen. INSERTED indeholder nye værdier, mens DELETED har gamle værdier.
Hvis du udsteder en SELECT fra tabelvariablen, er her, hvad du kan forvente:
Resultatet er som i figur 3, men det ser ind i fremtiden. Denne ser ind i fortiden. Hvis det er anderledes, er der gået noget galt ind imellem.
Den gode nyhed er, at du kan bruge gamle værdier i tabelvariablen til at gendanne den til dens tidligere tilstand. Men hvis det er det samme, så igen, er du god til at gå. Du kan markere OUTPUT-sætningen som en kommentar eller fjerne den, og derefter erstatte den midlertidige tabel med den originale tabel.
Flere oplysninger
- OUTPUT-klausul (Transact-SQL)
Brug TRY…CATCH til at håndtere fremtidige fejl
De foregående 3 tips er nyttige, når du laver og derefter tester din kode. Men vi ved alle, at vi ikke kan forudse alt. Derfor skal vi tilføje flere sikkerhedsnet til koden.
Apropos sikkerhedsnet, T-SQL har TRY…CATCH-fejlhåndteringsblokkene som C# og C++.
Lad os se på den ændrede kode fra det forrige eksempel:
BEGIN PRØV;WITH ComputedRatings AS ( SELECT a.TitleID ,ISNULL(CAST(CAST(AVG(CAST(b.Rating AS DECIMAL(3,2))) AS DECIMAL(3,2)) AS varchar (20)), 'Ingen brugerbedømmelser endnu') SOM Gennemsnitlig vurdering FRA titler a LEFT JOIN UserRatings b PÅ a.TitleID =b.TitleID GRUPPE AF a.TitleID ) OPDATERING Titler SÆT OverallUserRating =cr.AverageRating FRA Titler t INNER JOIN beregnet PÅ t.TitleID =cr.TitleIDEND PRØV BEGYNDE FANG SELECT ERROR_NUMBER() AS ErrorNumber ,ERROR_SEVERITY() AS ErrorSeverity ,ERROR_STATE() AS ErrorState ,ERROR_PROCEDURE() AS ErrorProcedure ,ERROR_OR_LINE()ASERERserror)ASEROR_LINE()ASERERserror)ASERERsError AS SLUT FANGST
Jeg ændrede koden ovenfor for at fremtvinge strengtrunkeringsfejlen. OverallUserRating kolonnen i Titler tabellen kan kun rumme op til 10 tegn. I CTE ændrede vi det til 20 tegn. Det passer ikke. CATCH-blokken overtager det øjeblik, hvor fejlen opstod og giver fejlinformationen.
Her er resultatet:
Vi udløste fejlen. Hvis du har brug for at fange uforudsete fejl under kørsel, er dette en måde at håndtere det på.
Flere oplysninger
- PRØV...CATCH (Transact-SQL)
Brug transaktionshåndtering
Endelig transaktioner. Det sikrer at gendanne alt til dets tidligere tilstand, før fejlen opstod, inklusive OPDATERING med JOIN og andre DML-sætninger. Dette er en god tilføjelse til tip #4 ovenfor.
Lad os ændre koden igen for at inkludere transaktioner:
BEGIN TRANSACTIONBEGIN PRØV;WITH ComputedRatings AS ( SELECT a.TitleID ,ISNULL(CAST(CAST(AVG(CAST(b.Rating AS DECIMAL(3,2))) AS DECIMAL(3,2)) AS varchar(20)), 'Ingen brugerbedømmelser endnu') SOM Gennemsnitlig vurdering FRA titler a LEFT JOIN UserRatings b ON a.TitleID =b.TitleID GROUP BY a.TitleID ) OPDATERING Titler SET OverallUserRating =cr.AverageRating FRA Titler t INNER JOIN Computed cr ON t.TitleID =cr.TitleID COMMIT TRANSACTIONEND PRØVBEGIN FANG SELECT ERROR_NUMBER() AS ErrorNumber ,ERROR_SEVERITY() AS ErrorSeverity ,ERROR_STATE() AS ErrorState ,ERROR_PROCEDURE() AS ErrorOR_LINE_ERERSerage TILBAGE TRANSACTIONEND FANGST
Det er det samme som i det foregående eksempel bortset fra transaktioner. Det vil således fremtvinge en strengtrunkeringsfejl. Det vil ikke gå forbi COMMIT TRANSACTION, men snarere i CATCH-blokken med ROLLBACK TRANSACTION for at vende værdierne tilbage til deres tidligere tilstande.
Dette er måden, hvis vi vil spille sikkert med opdateringer, indsættelser og sletninger.
Bemærk :Du kan designe enhver forespørgsel visuelt i et diagram ved hjælp af Query Builder-funktionen i dbForge Studio til SQL Server.
Flere oplysninger
- T-SQL bedste praksis
- Sådan skriver du T-SQL-forespørgsler som en professionel
Konklusion
Du har set syntaksen for SQL UPDATE med JOIN. Eksempler og 5 ubesværede tips oplyste dig yderligere. Kravene kan afvige fra, hvad eksemplerne viser, men du forstår pointen. Du kan stadig lave fejl. Det er dog muligt at reducere dem til næsten nul.
Hvorfor ikke anvende disse ideer til din situation?
Hvis dette indlæg var nyttigt, er du velkommen til at sprede ordet på dine foretrukne sociale medieplatforme. Og hvis du vil tilføje nogle gode ideer, er du velkommen til kommentarsektionen.