SQL обновляет поля одной таблицы из полей другой - PullRequest
106 голосов
/ 04 мая 2010

У меня есть две таблицы:

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

A всегда будет подмножеством B (то есть все столбцы A также находятся в B).

Я хочу обновить запись с определенным ID в B с их данными из A для всех столбцов A. Этот ID существует как в A, так и в B.

Существует ли синтаксис UPDATE или любой другой способ сделать это без указания имен столбцов, просто сказав "установить все столбцы A" ?

Я использую PostgreSQL, поэтому также допускается использование определенной нестандартной команды (однако, не рекомендуется).

Ответы [ 7 ]

200 голосов
/ 04 мая 2010

Вы можете использовать нестандартное предложение ОТ .

UPDATE b
SET column1 = a.column1,
  column2 = a.column2,
  column3 = a.column3
FROM a
WHERE a.id = b.id
AND b.id = 1
42 голосов
/ 25 апреля 2014

Вопрос старый, но я чувствовал, что лучший ответ еще не дан.

Существует ли синтаксис ОБНОВЛЕНИЕ ... без указания имен столбцов ?

Общее решение с динамическим SQL

Вам не нужно знать имена столбцов, за исключением некоторых уникальных столбцов, к которым нужно присоединиться (id в примере). Надежно работает для любого возможного углового случая, о котором я только могу подумать.

Это специфично для PostgreSQL. Я строю динамический код на основе information_schema , в частности таблицы information_schema.columns, которая определена в ANSI SQL, и большинство современных СУБД (за исключением Oracle) ее поддерживают. Но оператор DO с PL / pgSQL кодом, выполняющим динамический SQL, является полностью нестандартным синтаксисом PostgreSQL.

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$;

Предполагается, что соответствующий столбец в b для каждого столбца в a, но не наоборот. b может иметь дополнительные столбцы.

WHERE b.id = 123 необязательно, чтобы обновить только выбранную строку.

SQL Fiddle.

Связанные ответы с дополнительным объяснением:

Частичные решения с простым SQL

Со списком общих столбцов

Вам все еще нужно знать список имен столбцов, которые разделяют обе таблицы. С синтаксическим ярлыком для обновления нескольких столбцов - короче, чем другие ответы, предложенные до сих пор в любом случае.

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;

SQL Fiddle.

Этот синтаксис был введен в Postgres 8.2 в декабре 2006 года, задолго до того, как был задан вопрос.
Более подробная информация в руководстве и соответствующий ответ на dba.SE:

Со списком столбцов в B

Если определены все столбцы A NOT NULL (но не обязательно B),
и вы знаете имена столбцов B (но не обязательно 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;

NATURAL LEFT JOIN объединяет строку из b, где все столбцы с одинаковыми именами содержат одинаковые значения. В этом случае нам не нужно обновление (ничего не меняется), и мы можем удалить эти строки в начале процесса (WHERE b.id IS NULL).
Нам все еще нужно найти подходящую строку, поэтому b.id = ab.id во внешнем запросе.

Скрипка SQL.

Это стандартный SQL , за исключением предложения FROM .
Он работает независимо от того, какой из столбцов действительно присутствует в A, но запрос не может различить фактические значения NULL и отсутствующие столбцы в A, поэтому он надежен только в том случае, если все столбцы в A определены NOT NULL .

Существует несколько возможных вариантов, в зависимости от того, что вы знаете об обеих таблицах.

22 голосов
/ 26 ноября 2014

Я работаю с базой данных IBM DB2 более десяти лет и сейчас пытаюсь изучить PostgreSQL.

Работает в PostgreSQL 9.3.4, но не работает в DB2 10.5:

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

Примечание. Основная проблема - это причина FROM, которая не поддерживается в DB2, а также не поддерживается в ANSI SQL.

Работает в DB2 10.5, но НЕ работает в PostgreSQL 9.3.4:

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

НАКОНЕЦ! Он работает как на PostgreSQL 9.3.4, так и на 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)
7 голосов
/ 16 мая 2014

Это отличная помощь. Код

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;

отлично работает.

отметил, что вам нужна скобка "" в

From "tbl_a" a

чтобы все заработало.

5 голосов
/ 04 мая 2010

Не обязательно то, что вы просили, но, возможно, может помочь использование наследования postgres?

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

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

Это позволяет избежать необходимости обновления B.

Но обязательно прочитайте все подробности .

В противном случае то, что вы просите, не считается хорошей практикой - динамические вещи, такие как представления с SELECT * ..., не приветствуются (так как такое небольшое удобство может сломать больше вещей, чем помочь), и то, что вы просите, будет эквивалентно команда UPDATE ... SET.

0 голосов
/ 04 мая 2010

Попробуйте подписку

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

РЕДАКТИРОВАНИЕ: - Обновить более одного столбца

Update A a, B b, SET a.column1=b.column1, a.column2=b.column2 where b.id=1
0 голосов
/ 04 мая 2010

вы можете построить и выполнить динамический SQL для этого, но это действительно не идеально

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...