Sử dụng CASE để chọn các cột trong truy vấn CẬP NHẬT?


11

Tôi có thể sử dụng CASEđể chọn cột nào sẽ hiển thị trong SELECTtruy vấn (Postgres), như vậy:

SELECT CASE WHEN val = 0 THEN column_x
            WHEN val = 1 THEN column_y
            ELSE 0
       END AS update, ...

Có một cái gì đó tương tự có thể khi thực hiện một UPDATEtruy vấn trong Postgres (tức là chọn cột nào sẽ được cập nhật)? Tôi giả sử không phải vì tôi không thể tìm thấy bất cứ điều gì về điều này, nhưng có lẽ ai đó có một cách thay thế thông minh (bên cạnh việc sử dụng một quy trình hoặc cập nhật từng cột bằng cách CASExác định xem giá trị của cột có nên được gán một giá trị mới hay chỉ đơn giản là gán lại giá trị hiện có giá trị). Nếu không có lựa chọn nào dễ dàng, tất nhiên tôi cũng sẽ chấp nhận đó là câu trả lời.

Thông tin thêm : Trong trường hợp của tôi, tôi có 14 cột tiềm năng có thể được cập nhật, chỉ có một cột được cập nhật trên mỗi hàng khớp (bảng cần cập nhật được nối với một cột khác trong truy vấn). Số lượng hàng để cập nhật rất có thể sẽ khác nhau, có thể là hàng chục hoặc hàng trăm. Tôi tin rằng các chỉ số được đưa ra cho các điều kiện tham gia.

Câu trả lời:


24

Nếu bạn chỉ định một cột nên được cập nhật thì nó sẽ luôn được cập nhật, nhưng bạn có thể thay đổi giá trị bạn đặt trong điều kiện và đặt lại các giá trị ban đầu tùy thuộc vào điều kiện của bạn. Cái gì đó như:

UPDATE some_table
SET    column_x = CASE WHEN should_update_x THEN new_value_for_x ELSE column_x END
     , column_y = CASE WHEN should_update_y THEN new_value_for_y ELSE column_y END
     , column_z = CASE WHEN should_update_z THEN new_value_for_z ELSE column_z END
FROM   ...

Vì vậy, nếu các điều kiện không phù hợp để cập nhật cho một cột cụ thể, bạn chỉ cần cung cấp lại giá trị hiện tại.

Xin lưu ý rằng mọi hàng được khớp sẽ thấy một bản cập nhật (ngay cả khi tất cả các cột kết thúc được đặt thành các giá trị mà chúng đã có) trừ khi bạn rõ ràng đưa ra tình huống này trong việc lọc các mệnh đề ON và WHERE, có thể là một vấn đề về hiệu suất (sẽ có là một ghi, các chỉ mục sẽ được cập nhật, kích hoạt thích hợp sẽ kích hoạt, ...) nếu không được giảm nhẹ.


Cảm ơn mẹo về mọi thứ đang được cập nhật, nếu điều này chậm, tôi có thể lấy gợi ý của @Colin để có nhiều tuyên bố cập nhật.
newenglander

Bạn có thể giảm thiểu vấn đề đó bằng cách đảm bảo các mệnh đề ON và WHERE của bạn lọc ra tất cả các hàng không cần thay đổi, nhưng điều đó có thể có nghĩa là lặp lại tất cả các điều kiện của bạn cả trong mệnh đề SET và mệnh đề WHERE (trừ khi có một kiểm tra tổng thể đơn giản hơn là 100% tương đương với tất cả các điều kiện kết hợp). Tại thời điểm đó phương pháp này có thể vẫn hiệu quả hơn, nhưng phương pháp cập nhật nhiều lần có thể dễ duy trì hơn.
David Spillett

Cũng lưu ý rằng việc cập nhật một cột thành cùng một giá trị sẽ khiến việc làm lại được tạo ra, xem orai INTERNals.wordpress.com/2010/11/04/ợi
Colin 't Hart

@Colin: Đúng vậy, mọi cập nhật sẽ chuyển qua nhật ký giao dịch của DB, bao gồm các cập nhật thực chất là NoOps do các trường cập nhật có cùng giá trị mà chúng có trước đây. Cũng như khả năng xảy ra sự cố hiệu suất ngay lập tức, đây có thể là một yếu tố quan trọng nếu sử dụng sao chép, sao lưu vi sai, vận chuyển nhật ký, v.v., vì các hoạt động cập nhật hàng bổ sung sẽ tăng không gian / băng thông cần thiết cho những hoạt động đó.
David Spillett

Cảm ơn cả hai bạn về những lời khuyên, trong trường hợp của tôi, tuyên bố cập nhật duy nhất hoạt động tốt.
newenglander

5

Bạn có bao nhiêu kết hợp cột khác nhau để cập nhật? Có bao nhiêu hàng của toàn bộ bảng sẽ được cập nhật? Các chỉ mục có sẵn để truy cập nhanh vào các hàng để cập nhật không?

Tùy thuộc vào câu trả lời cho những câu hỏi này, bạn có thể thực hiện nhiều câu lệnh cập nhật, một câu lệnh cho mỗi cột mà bạn muốn cập nhật và đặt điều kiện trên giá trị của cột đó trong mệnh đề where của bản cập nhật để hàng 0 được cập nhật nếu cột đó được cập nhật có giá trị sai.

Hãy thử và nghĩ dựa trên tập hợp, đừng cho rằng cập nhật cần cập nhật một hàng duy nhất được tìm thấy bởi khóa chính.


Cảm ơn câu trả lời. Tôi đã thêm một số thông tin vào câu hỏi của tôi, tôi hy vọng nó có thể hiểu được. Đó là một lựa chọn tốt với nhiều câu lệnh cập nhật (tôi thích một câu lệnh cập nhật hơn, nhưng tôi thấy có một lợi thế ở đó).
newenglander

Đây có thể là câu trả lời tôi đang tìm kiếm nhưng ý bạn là đặt cập nhật cột_x = new_value_for_x trong đó @val = 0. Tôi có thể thử nghiệm một cái gì đó như thế. Trông buồn cười. Sẽ không dễ thực hiện hơn nếu val = 0 bắt đầu cập nhật cột_x = new_value_for_x, v.v.
CashCow

-1
update Practicing  -- table you will be updating
 set email = case -- column you will be updating
    when FName = 'Glenn' then 'Ace@Assasin.com'
       when FName = 'Riddick' then 'fallguy@Drunk.com'
       when FName = 'Jeffrey' then 'sorcerer@wizcom'
       else email
    end

Việc cập nhật này chỉ là một cột duy nhất, trong khi người hỏi muốn biết cách cập nhật các cột khác nhau tùy theo điều kiện.
Colin 't Hart
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.