Я новичок в PostgreSQL (и даже в Stackoverflow).
Скажем, у меня есть две таблицы Order и Delivery:

Order

id     product      address           delivery_id
--------------------------------------------------
1      apple        mac street        (null)
3      coffee       java island       (null)
4      window       micro street      (null)

Delivery

id     address
----------------

Delivery.id и Order.id - столбцы с автоматически увеличивающимся порядковым номером.
Таблица Delivery в настоящее время пуста.

Я хотел бы переместить Order.address в Delivery.address, а его Delivery.id в Order.delivery_id, чтобы достичь этого состояния:

Order

id     product      address           delivery_id
--------------------------------------------------
1      apple        mac street        1
5      coffee       java island       2
7      window       micro street      3

Delivery

id     address
---------------------
1      mac street
2      java island
3      micro street

Затем я удалю Order.address.

Я нашел аналогичный вопрос для Oracle, но не смог преобразовать его в PostgreSQL:

Я по-прежнему считаю, что в Postgres можно использовать простой оператор SQL с предложением RETURNING и следующим за ним INSERT.

Я пробовал это (а также несколько вариантов):

WITH ids AS (
    INSERT INTO Delivery (address)
    SELECT address
    FROM Order
    RETURNING Delivery.id AS d_id, Order.id AS o_id
)
UPDATE Order
SET Delivery_id = d_id
FROM ids
WHERE Order.id = ids.o_id;

Последняя попытка не удалась:

ОШИБКА: отсутствует запись предложения FROM для таблицы "Доставка" СТРОКА 1: ... адрес Возврат заказа Delivery.id ...

Как это сделать правильно?

1
dobyek 3 Май 2021 в 02:20

2 ответа

Лучший ответ

Прежде всего, ORDER - это зарезервированное слово . Не используйте его как идентификатор. Предполагая вместо этого orders в качестве таблицы.

WITH ids AS (
   INSERT INTO delivery (address)
   SELECT DISTINCT address
   FROM   orders
   ORDER  BY address -- optional
   RETURNING *
   )
UPDATE orders o
SET    delivery_id = i.id
FROM   ids i
WHERE  o.address = i.address;

Вы должны учитывать возможные дубликаты в order.address. SELECT DISTINCT создает уникальные адреса.

Во внешнем UPDATE теперь мы можем снова присоединиться к address, потому что delivery.address уникален. Вероятно, вам следует оставить это за пределами этого оператора и добавить UNIQUE ограничение на столбец.

Фактически приводит к связи "один ко многим" между delivery и orders. Одна строка в delivery может иметь много соответствующих строк в orders. Рассмотрите возможность обеспечения этого, добавив FOREIGN KEY ограничение соответственно.

Преимущество этого оператора заключается в том, что он начинается с пустой таблицы delivery. Если бы delivery не был пустым, нам пришлось бы работать с UPSERT вместо INSERT. Видеть:

Связанный:

О причине появившегося сообщения об ошибке:

По возможности используйте исключительно легальные идентификаторы в нижнем регистре. Видеть:

3
Erwin Brandstetter 3 Май 2021 в 00:32

Вы не можете вернуть столбцы из отношения FROM в предложении RETURNING запроса CTE. Вам нужно будет либо управлять этим с помощью курсора, либо добавить столбец order_id в таблицу Доставка , примерно так:

ALTER TABLE Delivery ADD COLUMNN order_id INTEGER:

INSERT INTO Delivery (address, order_id)
    SELECT address, id
    FROM Order
;

WITH q_ids AS
(
    SELECT id, order_id
    FROM Deliery
)
UPDATE Order
SET delivery_id = q_ids.id
FROM q_ids
WHERE Order.id = q_ids.order_id;
1
Don R 3 Май 2021 в 00:08