Database
 sql >> Teknologi Basis Data >  >> RDS >> Database

5 Tips Tanpa Repot untuk Menggunakan Pernyataan SQL UPDATE dengan JOIN

“Ups! Salahku." Berapa kali Anda mengatakan ini setelah SQL UPDATE salah? Masalahnya, jika Anda tidak hati-hati, pembaruan tabel dapat memiliki konsekuensi serius dalam bentuk pernyataan DELETE. Ini bisa menjadi lebih buruk jika Anda memperumitnya dengan menggunakan UPDATE dengan JOIN. Itu sebabnya Anda perlu memikirkannya sebelum menekan Execute atau menekan CTRL-E.

Jadi, hari ini Anda akan belajar cara membuat kode UPDATE SQL Anda dengan JOIN tanpa repot dan tidak pernah mengatakan “Ups! Burukku” lagi.

Tapi sebelum kita berlatih, kita mulai dengan sintaks. Ini juga akan membuat pemula kami merasa betah tentang SQL Server UPDATE dengan JOIN. Kemudian, kami akan menyiapkan beberapa data dan beberapa contoh. Dan terakhir, periksa tips keamanannya.

[sendpulse-form id="12968″]

SQL PERBARUI JOIN Syntax

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]

Kami perlu merinci beberapa poin dari ini.

  1. Kami dapat memperbarui tabel satu per satu untuk setidaknya 1 kolom atau beberapa kolom.
  2. Kami membutuhkan klausa FROM untuk menambahkan JOIN. Objek dalam klausa FROM mungkin sama atau mungkin tidak sama dengan objek yang sedang diperbarui.
  3. Kita bisa menggunakan INNER atau OUTER JOIN (lihat contoh nanti).
  4. Kami hanya dapat memperbarui sebagian data menggunakan klausa WHERE.

Sebelum kita memiliki contoh, mari kita siapkan datanya.

Data Uji Kami

Untuk pecinta film, mari buat database judul film dengan peringkat pengguna.

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

Sekarang kita memiliki database dan tabel, mari kita masukkan beberapa 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')
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

PERBARUI SQL Server dengan BERGABUNG Contoh

Kami akan memeriksa contoh berbeda yang memiliki tujuan yang sama untuk memperbarui OverallUserRating di Judul meja. Rating bisa 1 sampai 5. OverallUserRating adalah rata-rata dari semua peringkat untuk sebuah judul film.

Inilah keadaan awal tabel:

PERBARUI KIRI GABUNG Contoh

-- 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

Pernyataan SELECT pertama menghitung rating rata-rata per judul film berdasarkan UserRatings meja. Hasilnya dibuang ke tabel sementara bernama #ComputedRatings . Saat kami menggunakan INNER JOIN, judul film tanpa peringkat akan dibuang.

Dalam pernyataan UPDATE, Judul tabel diperbarui menggunakan LEFT JOIN dari #ComputedRatings meja sementara. Jika peringkat rata-rata null , nilainya menjadi No Rating . Dalam sampel kami, Captain America:Civil War belum memiliki peringkat pengguna – lihat Gambar 2.

Contoh SQL UPDATE INNER JOIN

Begini caranya:

-- 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

Saat Anda menjalankan kode di atas, hasilnya akan sama seperti pada Gambar 2. Tapi apa perbedaan dari kedua kode tersebut?

  • Pernyataan SELECT pertama menganggap peringkat pengguna NULL tidak seperti contoh LEFT JOIN kami sebelumnya. Itu tidak membuang judul film tanpa peringkat pengguna. Jadi, kali ini, Tanpa Peringkat nilai untuk Captain America:Civil War dianggap sudah.
  • INNER JOIN dengan penetapan langsung AverageRating nilai lebih tepat karena semua TitleID diperhitungkan.

Sekarang, sebagai ganti tabel sementara, ekspresi tabel umum (CTE) juga dapat digunakan. Berikut kode yang dimodifikasi:

-- 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

Informasi Lebih Lanjut

  • Panduan Utama Anda untuk SQL JOIN:INNER JOIN – Bagian 1
  • Panduan Utama Anda untuk SQL JOIN:OUTER JOIN – Bagian 2

Menggunakan Pembaruan Perintah dengan Gabung Aman (5 Kiat)

Keamanan mengacu pada pembaruan catatan yang dimaksudkan. Juga, ini tentang TIDAK menyentuh catatan yang tidak ingin kami perbarui. Di sini, kita akan menangani 5 skenario:

Lihat Catatan Pertama dengan Pernyataan SELECT

Tip ini sangat cocok untuk beberapa catatan. Jadi, sebelum Anda memengaruhi catatan untuk memperbarui, coba ini:

Itu mudah dilakukan. Dan jika terlihat bagus, batalkan komentar pada klausa UPDATE dan SET. Tandai klausa SELECT sebagai komentar. Kemudian, Anda baik untuk pergi. Dengan cara ini Anda meminimalkan kontrol kerusakan karena bersikap proaktif.

Lakukan Uji Coba Menggunakan Tabel Sementara

Merasa tidak yakin jika kesalahan mungkin terjadi? Kemudian cobalah untuk membuang catatan tabel yang ingin Anda perbarui ke dalam tabel sementara. Setelah itu, lakukan uji coba dari sana.

Apakah tidak ada kesalahan runtime? Apakah hasilnya terlihat bagus? Kemudian, ganti tabel sementara dengan tabel asli. Dengan cara ini, Anda tahu tidak akan ada kesalahan runtime di sepanjang proses.

Juga, perhatikan bahwa tabel sementara adalah salah satu cara untuk menyimpan salinan tabel asli. Anda juga dapat menggunakan tabel yang dioptimalkan memori atau cadangan database. Dengan cadangan basis data, Anda memiliki lebih banyak kebebasan untuk bermain dengan catatan yang perlu Anda perbarui. Namun kekurangannya adalah ruang penyimpanan.

Informasi Lebih Lanjut

  • BUAT TABEL (Transact-SQL) – Tabel Sementara

Coba Tambahkan Klausa OUTPUT ke UPDATE

Apakah Anda ingin kembali ke masa lalu sebelum menjalankan pembaruan? Jika Anda skeptis, Anda dapat menggunakan klausa OUTPUT dan melihat masa lalu dan masa kini. Dalam contoh di bawah ini, variabel tabel berfungsi untuk membuang nilai sebelumnya dan sekarang setelah pembaruan. Anda kemudian dapat PILIH variabel tabel untuk melihat hasilnya:

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

Beberapa hal yang perlu diperhatikan tentang kode ini:

  • Variabel tabel berfungsi sebagai wadah dari nilai sebelumnya dan sekarang.
  • Pembaruan biasa dengan CTE sedang berlangsung. Kami masih menggunakan tabel sementara untuk bermain aman.
  • Klausa OUTPUT berlaku untuk membuang nilai sebelumnya dan sekarang ke dalam variabel tabel. INSERTED berisi nilai baru, sedangkan DELETED memiliki nilai lama.

Jika Anda mengeluarkan SELECT dari variabel tabel, inilah yang mungkin Anda harapkan:

Hasilnya seperti Gambar 3, tetapi terlihat ke depan. Yang ini melihat ke masa lalu. Jika berbeda, berarti ada yang salah di antaranya.

Kabar baiknya adalah Anda dapat menggunakan nilai lama dalam variabel tabel untuk mengembalikannya ke keadaan sebelumnya. Tetapi jika itu sama, sekali lagi, Anda baik-baik saja. Anda dapat menandai klausa OUTPUT sebagai komentar atau menghapusnya, lalu mengganti tabel sementara dengan tabel asli.

Informasi Lebih Lanjut

  • Klausa OUTPUT (Transact-SQL)

Gunakan TRY…CATCH untuk Menangani Kesalahan di Masa Depan

3 tips sebelumnya berguna saat Anda membuat dan kemudian menguji kode Anda. Tapi kita semua tahu bahwa kita tidak bisa mengantisipasi semuanya. Oleh karena itu, kita perlu menambahkan lebih banyak jaring pengaman ke dalam kode.

Berbicara tentang jaring pengaman, T-SQL memiliki blok penanganan kesalahan TRY…CATCH seperti C# dan C++.

Mari kita lihat kode yang dimodifikasi dari contoh sebelumnya:

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

Saya mengubah kode di atas untuk memaksa kesalahan pemotongan string. Peringkat Pengguna Keseluruhan kolom di Judul tabel hanya dapat menampung hingga 10 karakter. Di CTE, kami mengubahnya menjadi 20 karakter. Itu tidak akan cocok. Blok CATCH akan mengambil alih saat terjadinya kesalahan dan memberikan informasi kesalahan.

Ini hasilnya:

Kami memicu kesalahan. Jika Anda perlu menemukan kesalahan yang tidak terduga selama waktu proses, ini adalah salah satu cara untuk menanganinya.

Informasi Lebih Lanjut

  • COBA…CATCH (Transact-SQL)

Gunakan Penanganan Transaksi

Terakhir, transaksi. Ini memastikan untuk mengembalikan semuanya ke keadaan sebelumnya sebelum kesalahan terjadi, termasuk UPDATE dengan JOIN dan pernyataan DML lainnya. Ini adalah tambahan yang bagus untuk Tip #4 di atas.

Mari kita ubah kode lagi untuk memasukkan transaksi:

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

Sama seperti pada contoh sebelumnya kecuali untuk transaksi. Dengan demikian, itu akan memaksa kesalahan pemotongan string. Itu tidak akan melewati COMMIT TRANSACTION, melainkan di blok CATCH dengan ROLLBACK TRANSACTION untuk mengembalikan nilai ke status sebelumnya.

Beginilah caranya jika kita ingin bermain aman dengan pembaruan, penyisipan, dan penghapusan.

Catatan :Anda dapat mendesain kueri apa pun secara visual dalam diagram menggunakan fitur Pembuat Kueri dari dbForge Studio untuk SQL Server.

Informasi Lebih Lanjut

  • Praktik Terbaik T-SQL
  • Cara Menulis Kueri T-SQL seperti Profesional

Kesimpulan

Anda telah melihat sintaks SQL UPDATE dengan JOIN. Contoh dan 5 tips tanpa kerumitan mencerahkan Anda lebih jauh. Persyaratannya mungkin berbeda dari contoh yang ada, tetapi Anda mengerti maksudnya. Anda masih bisa membuat kesalahan. Namun, dimungkinkan untuk menguranginya hingga mendekati nol.

Mengapa tidak menerapkan ide-ide ini pada situasi Anda?

Jika posting ini bermanfaat, jangan ragu untuk menyebarkan berita di platform media sosial favorit Anda. Dan jika Anda ingin menambahkan beberapa ide hebat, Anda dipersilakan di bagian Komentar.


  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. Tindak lanjut #1 pada pencarian wildcard terkemuka

  2. Cara Membuat Kluster Amazon Aurora

  3. Pengenalan Pola Baris dalam SQL

  4. Diagram ER di Meja Kerja IRI

  5. Solusi tantangan generator seri angka – Bagian 3