Làm cách nào tôi có thể thực hiện một câu lệnh CẬP NHẬT với THAM GIA trong SQL Server?


1314

Tôi cần cập nhật bảng này trong SQL Server với dữ liệu từ bảng 'cha mẹ' của nó, xem bên dưới:

Bảng: bán

id (int)
udid (int)
assid (int)

Bảng: ud

id  (int)
assid  (int)

sale.assidchứa giá trị chính xác để cập nhật ud.assid.

Truy vấn nào sẽ làm điều này? Tôi đang nghĩ về một joinnhưng tôi không chắc nếu nó có thể.


3
Bạn đang sử dụng RDBMS nào? MySQL, SQL Server, Oracle, PostgreSQL hay cái gì khác?
Chris J

một số quan hệ giữa các bảng? Làm thế nào người ta có thể biết bản ghi nào từ việc bán tương ứng với bản ghi nào từ ud? Có dựa trên id là khóa chính trong cả hai bảng không?
Cătălin Pitiș

Làm thế nào bạn có thể cập nhật UD? Nó chỉ có assid và nó là ID riêng. Bạn có thể đưa ra một ví dụ về các giá trị thực tế tồn tại và các bản ghi bạn muốn thay đổi hoặc thêm vào như là kết quả của tập lệnh không?
Bernhard Hofmann


2
Bí danh người dùng trong truy vấn như stackoverflow.com/questions/982919/sql-update-query-USE-joins
Imran Muhammad

Câu trả lời:


2383

Cú pháp hoàn toàn phụ thuộc vào SQL DBMS mà bạn đang sử dụng. Dưới đây là một số cách để thực hiện điều đó trong ANSI / ISO (hay nên hoạt động trên mọi DBMS SQL), MySQL, SQL Server và Oracle. Xin lưu ý rằng phương pháp ANSI / ISO được đề xuất của tôi thường sẽ chậm hơn nhiều so với hai phương thức kia, nhưng nếu bạn đang sử dụng SQL DBMS khác với MySQL, SQL Server hoặc Oracle, thì đó có thể là cách duy nhất để đi (ví dụ: nếu SQL DBMS của bạn không hỗ trợ MERGE):

ANSI / ISO:

update ud 
     set assid = (
          select sale.assid 
          from sale 
          where sale.udid = ud.id
     )
 where exists (
      select * 
      from sale 
      where sale.udid = ud.id
 );

MySQL:

update ud u
inner join sale s on
    u.id = s.udid
set u.assid = s.assid

Máy chủ SQL:

update u
set u.assid = s.assid
from ud u
    inner join sale s on
        u.id = s.udid

PostgreSQL:

update ud
  set assid = s.assid
from sale s 
where ud.id = s.udid;

Lưu ý rằng bảng đích không được lặp lại trong FROMmệnh đề cho Postgres.

Oracle:

update
    (select
        u.assid as new_assid,
        s.assid as old_assid
    from ud u
        inner join sale s on
            u.id = s.udid) up
set up.new_assid = up.old_assid

SQLite:

update ud 
     set assid = (
          select sale.assid 
          from sale 
          where sale.udid = ud.id
     )
 where RowID in (
      select RowID 
      from ud 
      where sale.udid = ud.id
 );

3
Theo tôi thì MySQL set assid = s.assidphải như vậy set u.assid = s.assid.
dotancohen

2
Trong cú pháp ANSI, điều gì xảy ra nếu CHỌN sau khi =trả về nhiều hơn một hàng?
Vứt bỏ tài khoản

2
@ ThrowawayAccount3Million Nó có thể sẽ thất bại. AFAIK, loại hoạt động này sẽ mong đợi một giá trị vô hướng và sẽ đưa ra một lỗi nếu được đưa ra một kết quả thay thế.
Đức Phanxicô

6
Tôi muốn OP chọn một số tên tốt hơn cho bảng và cột của mình !! nó không dễ đọc / trực quan như vậy ...
S.Serpooshan

4
Postgre 9.3 chỉ hoạt động bằng cách sử dụngupdate ud set assid = s.assid
StackUnder

143

Điều này sẽ hoạt động trong SQL Server:

update ud 
set assid = sale.assid
from sale
where sale.udid = id

98

bưu điện

UPDATE table1
SET    COLUMN = value
FROM   table2,
       table3
WHERE  table1.column_id = table2.id
       AND table1.column_id = table3.id
       AND table1.COLUMN = value
       AND table2.COLUMN = value
       AND table3.COLUMN = value 

20
Câu trả lời sẽ hữu ích hơn nếu nó sử dụng tên bảng / cột được sử dụng trong câu hỏi. Tại sao có 3 bảng trong câu trả lời của bạn?
alfonx

50

Một cách tiếp cận SQL tiêu chuẩn sẽ là

UPDATE ud
SET assid = (SELECT assid FROM sale s WHERE ud.id=s.id)

Trên SQL Server, bạn có thể sử dụng phép nối

UPDATE ud
SET assid = s.assid
FROM ud u
JOIN sale s ON u.id=s.id

1
Với cái đầu tiên, bạn không thể so khớp trên 2+ cột, nhưng tham gia hoạt động rất tốt.
makciook

6
@makciook: hả? Bạn chỉ có thể thêm nhiều điều kiện trong WHEREmệnh đề nếu bạn muốn khớp trên các cột bổ sung.
siride 11/07/2015

2
Chỉ là một nit ... nhưng tôi nghĩ OP có nghĩa là sale.udid = ud.id. Và không bán.id.
Skippy VonDrake

39

PostgreSQL :

CREATE TABLE ud (id integer, assid integer);
CREATE TABLE sales (id integer, udid integer, assid integer);

UPDATE ud
SET assid = sales.assid
FROM sales
WHERE sales.id = ud.id;

26

Truy vấn cập nhật đơn giản hóa bằng cách sử dụng THAM GIA nhiều bảng.

   UPDATE
        first_table ft
        JOIN second_table st ON st.some_id = ft.some_id
        JOIN third_table tt  ON tt.some_id = st.some_id
        .....
    SET
        ft.some_column = some_value
    WHERE ft.some_column = 123456 AND st.some_column = 123456

Lưu ý - First_table, second_table, third_table và some_column như 123456 là tên bảng demo, tên cột và id. Thay thế chúng bằng tên hợp lệ.


16

Một ví dụ khác tại sao SQL không thực sự di động.

Đối với MySQL, nó sẽ là:

update ud, sale
set ud.assid = sale.assid
where sale.udid = ud.id;

Để biết thêm thông tin, hãy đọc cập nhật nhiều bảng: http://dev.mysql.com/doc/refman/5.0/en/update.html

UPDATE [LOW_PRIORITY] [IGNORE] table_references
    SET col_name1={expr1|DEFAULT} [, col_name2={expr2|DEFAULT}] ...
    [WHERE where_condition]

2
+1 về nhận xét "tại sao SQL không thực sự di động"! Tính di động rất mong manh đến nỗi chỉ cần khai báo một biến sẽ phá vỡ tính di động giữa nhiều công cụ cơ sở dữ liệu phổ biến.
Jeff Moden

8

Teradata Aster cung cấp một cách thú vị khác để đạt được mục tiêu:

MERGE INTO ud --what trable should be updated
USING sale -- from what table/relation update info should be taken
ON ud.id = sale.udid --join condition
WHEN MATCHED THEN 
    UPDATE SET ud.assid = sale.assid; -- how to update

8

Tôi đã nghĩ rằng SQL-Server một trong bài đăng hàng đầu sẽ hoạt động cho Sybase vì cả hai đều là T-SQL nhưng tiếc là không.

Đối với Sybase, tôi thấy bản cập nhật cần phải nằm trên bảng chứ không phải bí danh:

update ud
set u.assid = s.assid
from ud u
    inner join sale s on
        u.id = s.udid

7

Câu lệnh sau với từ khóa TỪ được sử dụng để cập nhật nhiều hàng có liên kết

UPDATE users 
set users.DivisionId=divisions.DivisionId
from divisions join users on divisions.Name=users.Division

7

MySQL

Bạn sẽ có hiệu suất tốt nhất nếu bạn quên mệnh đề where và đặt tất cả các điều kiện trong biểu thức ON.

Tôi nghĩ điều này là do truy vấn trước tiên phải tham gia các bảng sau đó chạy mệnh đề where trên đó, vì vậy nếu bạn có thể giảm những gì được yêu cầu để tham gia thì đó là cách nhanh nhất để có kết quả / thực hiện udpate.

Thí dụ

Kịch bản

Bạn có một bảng người dùng. Họ có thể đăng nhập bằng tên người dùng hoặc email hoặc account_number. Các tài khoản này có thể hoạt động (1) hoặc không hoạt động (0). Bảng này có 50000 hàng

Sau đó, bạn có một bảng người dùng để vô hiệu hóa cùng một lúc vì bạn phát hiện ra tất cả họ đã làm điều gì đó tồi tệ. Tuy nhiên, bảng này có một cột với tên người dùng, email và số tài khoản được trộn lẫn. Nó cũng có một chỉ báo "has_run" cần được đặt thành 1 (true) khi nó được chạy

Truy vấn

UPDATE users User
    INNER JOIN
        blacklist_users BlacklistUser
        ON
        (
            User.username = BlacklistUser.account_ref
            OR
            User.email = BlacklistedUser.account_ref
            OR
            User.phone_number = BlacklistUser.account_ref
            AND
            User.is_active = 1
            AND
            BlacklistUser.has_run = 0
        )
    SET
        User.is_active = 0,
        BlacklistUser.has_run = 1;

Lý luận

Nếu chúng ta phải tham gia chỉ với các điều kiện HOẶC thì về cơ bản, nó sẽ cần kiểm tra mỗi hàng 4 lần để xem nó có nên tham gia không và có khả năng trả về nhiều hàng hơn nữa không. Tuy nhiên, bằng cách cung cấp cho nó nhiều điều kiện hơn, nó có thể "bỏ qua" rất nhiều hàng nếu chúng không đáp ứng tất cả các điều kiện khi tham gia.

Tặng kem

Nó dễ đọc hơn. Tất cả các điều kiện ở một nơi và các hàng để cập nhật ở một nơi


4

Và trong MS TRUY CẬP:

UPDATE ud 
INNER JOIN sale ON ud.id = sale.udid
SET ud.assid = sale.assid;

1
Để thận trọng, SET phải đến ngay sau định nghĩa recordset! Tôi vừa cố gắng tìm ra một kịch bản tương tự trong cơ sở dữ liệu Access, cần một mệnh đề WHERE (nó sẽ không chấp nhận nó như một điều kiện BẬT hợp lệ). WHERE phải đến cuối cùng để tránh lỗi cú pháp.
Dodecaphone


3
UPDATE tblAppraisalBasicData
SET tblAppraisalBasicData.ISCbo=1
FROM tblAppraisalBasicData SI INNER JOIN  aaa_test RAN ON SI.EmpID = RAN.ID

3

Hãy thử cái này, tôi nghĩ rằng nó sẽ làm việc cho bạn

update ud

set ud.assid = sale.assid

from ud 

Inner join sale on ud.id = sale.udid

where sale.udid is not null

2

Đối với SQLite, sử dụng thuộc tính RowID để thực hiện cập nhật:

update Table set column = 'NewValue'
where RowID = 
(select t1.RowID from Table t1
join Table2 t2 on t1.JoinField = t2.JoinField
where t2.SelectValue = 'FooMyBarPlease');

1
Bạn có thể giải thích điều này một chút?
Mohammed Noureldin

1
@MohammedNoureldin Tôi sẽ cố gắng giải thích. Vấn đề là làm thế nào để cập nhật một bảng với kết quả từ một truy vấn trên Tham gia bằng cách sử dụng cùng một bảng. Câu lệnh (chọn phụ) hoạt động như một phép nối và trả về một trường hệ thống, RowID, là một số duy nhất cho mỗi hàng trong một bảng. Vì lựa chọn phụ có thể trả về nhiều hàng, "trong đó RowID =" chọn một hàng đúng duy nhất từ ​​lựa chọn phụ kết quả và thực hiện cập nhật cho cột. Hãy cho tôi biết nếu bạn cần làm rõ hơn hoặc cần tìm ra một biến thể về chủ đề này.
KeithTheBiped
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.