Hỏi Đáp SQL------------ Không có câu hỏi nào là sơ đẳng --------

Update bảng từ Join và những điều cần lưu tâm

Khi ứng dụng ngày càng lớn và phức tạp, bạn sẽ gặp những trường hợp phải Update bảng với dữ liệu từ bảng nào đó, chứ không chỉ đơn thuần là những giá trị cố định. Khi ấy bạn không thể thực hiện câu lệnh Update truyền thống như "update bangA set c=1 where id=2". Trong trường hợp này bạn phải Join các bảng lại rồi sau đó mới Update bảng cần Update.

Có nhiều cách thức thực hiện yêu cầu này. Dưới đây là 3 cách phổ biến.


Bạn có thể thấy trường b của bảng @b1 đã được update với giá trị của trường b của bảng @b2.

- cách 1 ngắn gọn nhất
- cách 2 rõ ràng nhất
- cách 3 an toàn nhất

Quan sát giá trị bảng @b1 và @b2 ở ví dụ trên, bạn sẽ thấy quan hệ giữa 2 bảng này ở trường a là 1 - 1, nên kết quả đều tốt và không có gì phải băn khoăn. Nhưng nếu quan hệ này là 1 - n, bạn sẽ thấy rắc rối. Giả thử bảng @b2 có 2 dòng đều có a=1, vậy giá trị b để update cho bảng @b1 là giá trị nào? Xem ví dụ dưới đây, bảng @b1 được update bởi cách 1



Bạn có thể tự hỏi, tại sao trường b của bảng @b1 được update với giá trị là 7 chứ không phải 8?

Câu trả lời là với cách 1 và 2, hệ thống sẽ sử dụng giá trị đầu tiên mà nó gặp, trường hợp này là 7. Vấn đề là bạn không thể biết giá trị đầu tiên mà hệ thống gặp và nó có thể thay đổi tùy tình hình, mà cụ thể là hoàn toàn ngẫu nhiên. Tức bạn không thể biết giá trị mà bạn muốn update cho bảng @b2 là giá trị nào(7 hay 8). Đây là 1 trường hợp tạo bug khá phổ biến trong lập trình SQL.

Đây chính là ưu điểm của cách 3 với lệnh Merge. Nếu bạn sử dụng cách 3, trong trường hợp này, hệ thống sẽ báo lỗi, chứ không thầm lặng update với giá trị ngẫu nhiên như cách 1 và 2.

Tóm lại, trong trường hợp bạn biết chắc quan hệ giữa các bảng là 1 - 1, bạn có thể sử dụng cả 3 cách trên, nhưng nếu không chắc, tốt nhất bạn nên sử dụng cách 3. Sử dụng Merge có chút rắc rối, bạn có thể đọc thêm về cách thức sử dụng Merge mà tôi đã đề cập ở bài viết trước đây.

Dưới đây là toàn bộ mã cho bạn chạy thử

declare @b1 table (id int identity, a int, b int)
declare @b2 table (id int identity, a int, b int)
insert into @b1 values(8,5),(6,5),(1,2),(3,8)
insert into @b2 values(1,7),(3,9),(7,6),(1,8)
--- 2 bang ban dau
select * from @b1
select * from @b2

--1-- phuong phap thong thuong
update @b1 set b=b2.b
from @b1 b1
join @b2 b2 on b1.a=b2.a
/*
--2-- su dung cte 
;with cte as
(
select b1.*, b2.b as newvalue 
from @b1 b1
join @b2 b2 on b1.a=b2.a
)
update cte set b=newvalue

--3-- su dung merge
merge into @b1 t
using @b2 s on t.a=s.a
when matched 
then update set t.b=s.b;
*/
--- bang b1 sau khi update
select * from @b1


Không có nhận xét nào:

Đăng nhận xét