Поля оновлення 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.