2009-11-19 31 views
5

Tôi có một bảng regionkey:Việc trao đổi hai hàng DB mà không vi phạm các ràng buộc

areaid -- primary key, int 
region -- char(4) 
locale -- char(4) 

Toàn bộ phần còn lại của cơ sở dữ liệu là nước ngoài vừa khít với areaid. Trong bảng này có một chỉ mục trên (khu vực, miền địa phương) với một ràng buộc duy nhất.

Vấn đề là tôi có hai hồ sơ:

101 MICH DETR 
102 ILLI CHIC 

Và tôi cần phải trao đổi các (vùng, miền địa phương) các lĩnh vực giữa chúng, vì vậy mà tôi gió lên với:

101 ILLI CHIC 
102 MICH DETR 

Các cách tiếp cận ngây thơ sẽ không hoạt động vì nó vi phạm chỉ mục duy nhất trên vùng và ngôn ngữ:

update regionkey 
    set region='ILLI', locale='CHIC' where areaid = 101; -- FAILS 
update regionkey 
    set region='MICH', locale='DETR' where areaid = 102; 

Làm cách nào tôi có thể thực hiện việc này? Có cách nguyên tử nào để hoán đổi không? Gợi ý?

Trả lời

8

Bạn không thể trì hoãn việc kiểm tra ràng buộc trong SQL Server trên nhiều báo cáo (trừ khi bạn tắt) vì vậy bạn phải tránh những xung đột hoặc làm điều đó trong một tuyên bố

update 
    regionkey 
set 
    region= CASE areaid WHEN 101 THEN 'ILLI' ELSE 'MICH' END, 
    locale= CASE areaid WHEN 101 THEN 'CHIC' ELSE 'DETR' END 
where 
    areaid IN (101, 102); 

hay, thông thường hơn (trong một giao dịch cái này)

update regionkey 
    set region='AAAA', locale='BBBB' where areaid = 101; 
update regionkey 
    set region='MICH', locale='DETR' where areaid = 102; 
update regionkey 
    set region='ILLI', locale='CHIC' where areaid = 101; 

Chỉnh sửa: Tại sao không trao đổi khóa không phải là giá trị? Nó thường đạt được kết quả lành mạnh trừ khi khu vực có một số ý nghĩa

update 
    regionkey 
set 
    areaid = 203 - areaid 
where 
    areaid IN (101, 102); 
+0

Điều này có thể đủ điên rồ để hoạt động. Bạn có nghĩ rằng anh ta nên quấn nó trong một giao dịch? – Broam

+0

một lần chèn đơn lẻ là một giao dịch tiềm ẩn duy nhất anyway – gbn

+0

Chỉ cần một chút nhanh hơn tôi, @gbn ;-) – karlgrz

1

Đặt cược trước là thực hiện ba cập nhật. Cập nhật bản ghi đầu tiên thành một bộ giá trị tạm thời, cập nhật bản ghi thứ hai và sau đó cập nhật bản ghi đầu tiên lên các giá trị bạn muốn.

0

Bạn đã thử hành động đơn giản của việc gói nó trong một giao dịch?

Tôi hiểu rằng bạn có thể thiết lập các ràng buộc để cho phép nó chỉ thực thi ràng buộc ở cuối giao dịch nhưng tôi không chắc liệu các ràng buộc của bạn có được thiết lập theo cách đó hay không.

+1

Không có "hạn chế trì hoãn" trong SQL Server, trừ khi bạn sử dụng rõ ràng DISABLE mà là một tuyên bố DDL – gbn

+0

Tôi đã khai sáng, cảm ơn bạn. – Broam

0

Một gợi ý, có thể không phải là an toàn nhất cho bộ hồ sơ lớn, sẽ được thiết lập cả hồ sơ để '' cho cả khu vực & miền địa phương, và sau đó thực hiện hai câu lệnh cập nhật, một cho mỗi hồ sơ, như vậy:

UPDATE 
    regionkey 
SET 
    region = ' ', 
    locale = ' ' 
WHERE 
    areaid in (101,102) 

UPDATE 
    regionkey 
SET 
    region = 'ILLI', 
    locale = 'CHIC' 
WHERE 
    areaid = 101 

UPDATE 
    regionkey 
SET 
    region = 'MICH', 
    locale = 'DETR' 
WHERE 
    areaid = 102 

Như tôi đã nói, đây có lẽ không phải là cách an toàn nhất để đi, nhưng đối với một tập dữ liệu nhỏ, bạn nên OK.

CẬP NHẬT: Larry đã chỉ ra chính xác rằng câu lệnh UPDATE đầu tiên sẽ vi phạm ràng buộc UNIQUE. Sử dụng này để thay thế cho CẬP NHẬT đầu tiên:

UPDATE 
    regionkey 
SET 
    region = areaid, 
    locale = areaid 
WHERE 
    areaid in (101,102) 

Bằng cách này mỗi khu vực trung và miền địa phương là (hoặc nên là) độc đáo.

+0

Cùng một vấn đề - UPDATE ban đầu sẽ vi phạm UNIQUEness trên khu vực, miền địa phương. –

+0

Bạn ĐANG PHẢI !!! Tôi đã cập nhật câu trả lời của mình để phản ánh điều này. Tốt bắt, @Larry! – karlgrz

Các vấn đề liên quan