Поля оновлення SQL однієї таблиці з поля іншої


124

У мене дві таблиці:

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, тому певна нестандартна команда також приймається (однак, не бажана).


Я думаю, що це ти хочеш зробити, dba.stackexchange.com/a/58383
— zubair-0

Відповіді:


234

Ви можете використовувати нестандартний пункт FROM .

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

9
Питання полягає в тому, як це зробити, не вказуючи всі назви стовпців. (І я теж.)
— cluesque

2
Я погоджуюся з @cluesque, але ця відповідь є прекрасним способом використання значень в одному стовпчику таблиці як таблиці пошуку для заміни значень у стовпчику в іншій таблиці (див. SO 21657475 ), тому +1 ...
— Вікторія Стюарт

1
Для чого потрібен b.id = 1?
— ЯсірАзгар

1
@YasirAzgar b.id = 1 обмежує кількість рядків у b оновлюватися. Інакше ми б оновлювали кожен рядок у таблиці. Інколи, це може бути те, що ви хочете. Але первісне питання полягало в оновленні конкретного рядка в b.
— Скотт Бейлі

Це те, що мені було потрібно для моєї конкретної проблеми: оновлення стовпця однієї таблиці зі значеннями з стовпця з іншою таблицею.
— muad-dweeb

49

Питання старе, але я відчув, що найкращої відповіді ще не було.

Чи є UPDATEсинтаксис ... без вказівки назв стовпців ?

Загальне рішення з динамічним SQL

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

Це специфічно для PostgreSQL. Я будую динамічний код на основі інформаційної схеми , зокрема таблиці information_schema.columns, яка визначена в стандарті SQL, і більшість основних RDBMS (крім 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 році, задовго до того, як було задано питання. Деталі в посібнику.

Пов'язані:

Зі списком стовпців у 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у зовнішньому запиті.

db <> fiddle тут
Стара квадратна загадка.

Це стандартний SQL за винятком FROMпункту .
Він працює незалежно від того , яка з колонок на насправді присутній в A, але запит не може розрізняти між фактичними значеннями NULL і відсутніх стовпців в A, так що це тільки надійним , якщо всі стовпці Aвизначені NOT NULL.

Існує кілька можливих варіантів, залежно від того, що ви знаєте про обидві таблиці.


Сила SQL! Щойно помітив, коли ви додаєте круглі дужки у встановлений пункт ( SET (column1) = (a.column)) Postgres трактуватиме це як інший вид оновлення та видачі та помилки на кшталт цього:source for a multiple-column UPDATE item must be a sub-SELECT or ROW() expression
— Едгар Ортега

26

Я працюю з базою даних 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

Примітка: Основна проблема полягає з причини, яка не підтримується в 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)

3
Зауважте, що другий і третій запити не є повністю еквівалентними першому. Якщо в одному рядку не знайдено відповідного рядка B, перший оператор нічого не робить (оригінальний рядок залишається недоторканим), а інші два перезаписують стовпці зі значеннями NULL.
— Ервін Брандстетер

7

Це чудова допомога. Код

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

Не обов’язково те, що ви запитували, але, можливо, використання успадкування постгресів може допомогти?

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

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

Це дозволяє уникнути необхідності оновлення Б.

Але обов’язково прочитайте всі подробиці .

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


Я не впевнений, як спадщина вирішить це. Ви маєте на увазі додавання тригера оновлення для A, який також оновлює B? Я не хочу постійно синхронізувати A з B, лише за запитом. І в такому випадку я не можу використовувати тригери.
— Нір

2
Так, якщо це лише в певних випадках, то успадкування не буде працювати, і в такому випадку я раджу не підходити до динамічного запиту. (все ж є способи досягти цього за допомогою процедурних мов postgres. Також, якщо ви хочете використовувати тригери, ви можете їх також використовувати - додавши поле синхронізації, наприклад, тригер запуску лише тоді, коли воно встановлено).
— Нерозумне

0

ви можете створити та виконати динамічний sql для цього, але це справді не ідеально


Я про це думав. Я думав, що можу зробити свій запит сумісним із пізнішими змінами обох таблиць, але динамічний sql здається занадто складним, ніж просто вказати всі поля та забути про сумісність вперед.
— Nir

так, це буде складно, але його слід передати сумісним із пізнішими стовпцями, що додаються чи видаляються. Спершу потрібно виконати запит, щоб отримати імена стовпців з обох таблиць, потім зіставити назви стовпців, а потім записати динамічний sql, щоб зробити оновлення на основі відповідних назв стовпців. цікавий проект насправді :)
— Даніель Брінк

-4

Спробуйте слідкувати

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

Я не розумію, як він копіює колонку1, стовпчик2 та стовпець3. І мені потрібно чітко згадати колонку1.
— Nir

Не працює для мене. Я отримую таку помилку: ПОМИЛКА: помилка синтаксису біля або біля ","
— melbic

1
Цей нестандартний синтаксис буде працювати UPDATEв MySQL , але він недійсний для PostgreSQL.
— Ервін Брандстетер
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.