Các trường cập nhật SQL của một bảng từ các trường của một bảng khác


124

Tôi có hai bảng:

A [ID, column1, column2, column3]
B [ID, column1, column2, column3, column4]

Asẽ luôn là tập con của B(có nghĩa là tất cả các cột Acũng nằm trong B).

Tôi muốn cập nhật một kỷ lục với một cụ thể IDtrong Bdữ liệu của họ từ Acho tất cả các cột của A. Điều này IDtồn tại cả trong AB.

Có một UPDATEcú pháp hoặc bất kỳ cách nào khác để làm điều đó mà không chỉ định tên cột, chỉ cần nói "đặt tất cả các cột của A" ?

Tôi đang sử dụng PostgreSQL, do đó, một lệnh không chuẩn cụ thể cũng được chấp nhận (tuy nhiên, không được ưa thích).


Tôi nghĩ đây là những gì bạn muốn làm, dba.stackexchange.com/a/58383
zubair-0

Câu trả lời:


234

Bạn có thể sử dụng mệnh đề TỪ phi tiêu chuẩn .

UPDATE b
SET column1 = a.column1,
  column2 = a.column2,
  column3 = a.column3
FROM a
WHERE a.id = b.id
AND b.id = 1

9
Câu hỏi là hỏi về cách thực hiện mà không chỉ định tất cả các tên cột. (Và tôi cũng vậy.)
cluesque

2
Tôi đồng ý với @cluesque, nhưng câu trả lời này là một cách tuyệt vời để sử dụng các giá trị trong một cột trong bảng làm bảng tra cứu để thay thế các giá trị trong một cột trong một bảng khác (xem SO 21657475 ), vì vậy +1 ...
Victoria Stuart

1
Tại sao b.id = 1 là cần thiết?
YasirAzgar

1
@YasirAzgar b.id = 1 là giới hạn những hàng nào trong b được cập nhật. Nếu không, chúng tôi sẽ cập nhật mỗi hàng trong bảng. Thỉnh thoảng, đó có thể là những gì bạn muốn. Nhưng câu hỏi ban đầu là cập nhật một hàng cụ thể trong b.
Scott Bailey

Đây là điều tôi cần cho vấn đề cụ thể của mình: cập nhật cột của một bảng với các giá trị từ cột có tên khác của bảng khác.
muad-dweeb

49

Câu hỏi đã cũ nhưng tôi cảm thấy câu trả lời hay nhất chưa được đưa ra.

Có một UPDATEcú pháp ... mà không chỉ định tên cột ?

Giải pháp chung với SQL động

Bạn không cần biết bất kỳ tên cột nào ngoại trừ một số cột duy nhất để tham gia (id trong ví dụ). Hoạt động đáng tin cậy cho bất kỳ trường hợp góc có thể tôi có thể nghĩ đến.

Điều này là cụ thể cho PostgreSQL. Tôi đang xây dựng mã động dựa trên information_schema , đặc biệt là bảng information_schema.columns, được định nghĩa trong tiêu chuẩn SQL và hầu hết RDBMS chính (trừ Oracle) đều có nó. Nhưng một DOcâu lệnh với mã PL / pgSQL thực thi SQL động hoàn toàn là cú pháp PostgreQuery không chuẩn.

DO
$do$
BEGIN

EXECUTE (
SELECT
  'UPDATE b
   SET   (' || string_agg(        quote_ident(column_name), ',') || ')
       = (' || string_agg('a.' || quote_ident(column_name), ',') || ')
   FROM   a
   WHERE  b.id = 123
   AND    a.id = b.id'
FROM   information_schema.columns
WHERE  table_name   = 'a'       -- table name, case sensitive
AND    table_schema = 'public'  -- schema name, case sensitive
AND    column_name <> 'id'      -- all columns except id
);

END
$do$;

Giả sử một cột phù hợp bcho mỗi cột trong a, nhưng không phải là cách khác.bcó thể có các cột bổ sung.

WHERE b.id = 123 là tùy chọn, để cập nhật một hàng đã chọn.

Câu đố SQL.

Câu trả lời liên quan với nhiều lời giải thích:

Giải pháp một phần với SQL đơn giản

Với danh sách các cột được chia sẻ

Bạn vẫn cần biết danh sách các tên cột mà cả hai bảng chia sẻ. Với một phím tắt cú pháp để cập nhật nhiều cột - ngắn hơn những câu trả lời khác được đề xuất cho đến nay trong mọi trường hợp.

UPDATE b
SET   (  column1,   column2,   column3)
    = (a.column1, a.column2, a.column3)
FROM   a
WHERE  b.id = 123    -- optional, to update only selected row
AND    a.id = b.id;

Câu đố SQL.

Cú pháp này được giới thiệu với Postgres 8.2 vào năm 2006, rất lâu trước khi câu hỏi được hỏi. Chi tiết trong hướng dẫn.

Liên quan:

Với danh sách các cột trong B

Nếu tất cả các cột Ađược xác định NOT NULL(nhưng không nhất thiết B)
bạn biết tên cột của B(nhưng không nhất thiết A).

UPDATE b
SET   (column1, column2, column3, column4)
    = (COALESCE(ab.column1, b.column1)
     , COALESCE(ab.column2, b.column2)
     , COALESCE(ab.column3, b.column3)
     , COALESCE(ab.column4, b.column4)
      )
FROM (
   SELECT *
   FROM   a
   NATURAL LEFT JOIN  b -- append missing columns
   WHERE  b.id IS NULL  -- only if anything actually changes
   AND    a.id = 123    -- optional, to update only selected row
   ) ab
WHERE b.id = ab.id;

Các NATURAL LEFT JOINtham gia một hàng từ bđó tất cả các cột cùng tên giữ các giá trị giống nhau. Chúng tôi không cần cập nhật trong trường hợp này (không có gì thay đổi) và có thể loại bỏ những hàng đó sớm trong quy trình ( WHERE b.id IS NULL).
Chúng ta vẫn cần tìm một hàng phù hợp, vì vậyb.id = ab.id trong truy vấn bên ngoài.

db <> fiddle ở đây
sqlfiddle .

Đây là SQL tiêu chuẩn ngoại trừ FROMmệnh đề .
Nó hoạt động bất kể cột nào thực sự có mặt trong đó A, nhưng truy vấn không thể phân biệt giữa các giá trị NULL thực tế và các cột bị thiếu A, vì vậy nó chỉ đáng tin cậy nếu tất cả các cột trong Ađược xác địnhNOT NULL .

Có nhiều biến thể có thể, tùy thuộc vào những gì bạn biết về cả hai bảng.


Sức mạnh của SQL! Chỉ cần chú ý khi bạn thêm dấu ngoặc đơn trong mệnh đề set ( SET (column1) = (a.column)) Postgres sẽ coi nó như một loại cập nhật khác và cho và lỗi như thế này:source for a multiple-column UPDATE item must be a sub-SELECT or ROW() expression
Edgar Ortega

26

Tôi đã làm việc với cơ sở dữ liệu IBM IBM trong hơn một thập kỷ và bây giờ đang cố gắng tìm hiểu PostgreSQL.

Nó hoạt động trên PostgreSQL 9.3.4, nhưng không hoạt động trên DB2 10.5:

UPDATE B SET
     COLUMN1 = A.COLUMN1,
     COLUMN2 = A.COLUMN2,
     COLUMN3 = A.COLUMN3
FROM A
WHERE A.ID = B.ID

Lưu ý: Vấn đề chính là TỪ nguyên nhân không được hỗ trợ trong DB2 và cũng không phải trong ANSI SQL.

Nó hoạt động trên DB2 10.5, nhưng KHÔNG hoạt động trên PostgreSQL 9.3.4:

UPDATE B SET
    (COLUMN1, COLUMN2, COLUMN3) =
               (SELECT COLUMN1, COLUMN2, COLUMN3 FROM A WHERE ID = B.ID)

CUỐI CÙNG! Nó hoạt động trên cả PostgreSQL 9.3.4 và DB2 10.5:

UPDATE B SET
     COLUMN1 = (SELECT COLUMN1 FROM A WHERE ID = B.ID),
     COLUMN2 = (SELECT COLUMN2 FROM A WHERE ID = B.ID),
     COLUMN3 = (SELECT COLUMN3 FROM A WHERE ID = B.ID)

3
Lưu ý rằng truy vấn thứ hai và thứ ba không hoàn toàn tương đương với truy vấn đầu tiên. Nếu không tìm thấy hàng phù hợp B, câu lệnh đầu tiên không làm (hàng gốc vẫn chưa được xử lý), trong khi hai cột khác ghi đè lên bằng các giá trị NULL.
Erwin Brandstetter

7

Đây là một trợ giúp lớn. Mật mã

UPDATE tbl_b b
SET   (  column1,   column2,   column3)
    = (a.column1, a.column2, a.column3)
FROM   tbl_a a
WHERE  b.id = 1
AND    a.id = b.id;

hoạt động hoàn hảo.

lưu ý rằng bạn cần một dấu ngoặc "" trong

From "tbl_a" a

Để làm cho nó hoạt động.


5

Không nhất thiết là những gì bạn yêu cầu, nhưng có lẽ sử dụng thừa kế postgres có thể giúp đỡ?

CREATE TABLE A (
    ID            int,
    column1       text,
    column2       text,
    column3       text
);

CREATE TABLE B (
    column4       text
) INHERITS (A);

Điều này tránh sự cần thiết phải cập nhật B.

Nhưng hãy chắc chắn để đọc tất cả các chi tiết .

Mặt khác, những gì bạn yêu cầu không được coi là một thông lệ tốt - những thứ năng động như quan điểm SELECT * ...không được khuyến khích (vì sự tiện lợi nhỏ như vậy có thể phá vỡ nhiều thứ hơn là những thứ giúp đỡ) và những gì bạn yêu cầu sẽ tương đương với UPDATE ... SETlệnh.


Tôi không chắc làm thế nào thừa kế sẽ giải quyết điều này. Bạn có nghĩa là thêm một kích hoạt cập nhật cho A cũng cập nhật B? Tôi không muốn đồng bộ hóa A với B mọi lúc, chỉ khi có yêu cầu. Và trong trường hợp như vậy, tôi không thể sử dụng các kích hoạt.
NĂM

2
Có, nếu chỉ trong một số trường hợp nhất định thì tính kế thừa sẽ không hoạt động và trong trường hợp đó tôi khuyên bạn không nên tiếp cận truy vấn động. .
Không hợp lý

0

bạn có thể xây dựng và thực thi sql động để làm điều này, nhưng nó thực sự không lý tưởng


Tôi nghĩ về điều đó. Tôi nghĩ rằng tôi có thể làm cho truy vấn của mình tuân thủ các thay đổi sau này cho cả hai bảng, nhưng sql động dường như quá phức tạp so với việc chỉ định tất cả các trường và quên đi khả năng tương thích về phía trước.

có, nó sẽ phức tạp, nhưng phải tương thích về phía trước với các cột sau được thêm hoặc xóa. Trước tiên, bạn phải thực hiện một truy vấn để lấy tên cột từ cả hai bảng, sau đó khớp tên cột và sau đó viết sql động để thực hiện cập nhật dựa trên tên cột phù hợp. một dự án thú vị thực sự :)
Daniel Brink

-4

Hãy thử làm theo

Update A a, B b, SET a.column1=b.column1 where b.id=1

EDITED: - Cập nhật nhiều hơn một cột

Update A a, B b, SET a.column1=b.column1, a.column2=b.column2 where b.id=1

Tôi không hiểu làm thế nào nó sao chép cột1, cột2 và cột3. Và tôi cần phải đề cập rõ ràng đến cột1.

Không làm việc cho tôi. Tôi nhận được lỗi sau: LRI: lỗi cú pháp tại hoặc gần ","
melbic

1
Cú pháp không chuẩn này sẽ hoạt động UPDATEtrong MySQL , nhưng nó không hợp lệ đối với PostgreSQL.
Erwin Brandstetter
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.