2016-11-18 7 views
2

У меня есть три таблицы:Как сделать глубокую копию с помощью одного запроса PostgreSQL?

CREATE TABLE offers 
(
    id serial NOT NULL PRIMARY KEY, 
    title character varying(1000) NOT NULL DEFAULT ''::character varying 
); 

CREATE TABLE items 
(
    id serial NOT NULL PRIMARY KEY, 
    offer_id integer NOT NULL, 
    title character varying(1000) NOT NULL DEFAULT ''::character varying, 
    CONSTRAINT items_offer_id_fkey FOREIGN KEY (offer_id) 
     REFERENCES offers (id) 
); 

CREATE TABLE sizes 
(
    id serial NOT NULL PRIMARY KEY, 
    item_id integer NOT NULL, 
    title character varying(1000) NOT NULL DEFAULT ''::character varying, 
    CONSTRAINT sizes_item_id_fkey FOREIGN KEY (item_id) 
     REFERENCES items (id) 
); 

У меня есть 1 предложение, которое имеет 2 пунктов. Каждый элемент имеет 2 размера:

INSERT INTO offers (title) VALUES ('My Offer'); 
INSERT INTO items (offer_id, title) VALUES (1, 'First Item'); 
INSERT INTO items (offer_id, title) VALUES (1, 'Second Item'); 
INSERT INTO sizes (item_id, title) VALUES (1, 'First Size of Item #1'); 
INSERT INTO sizes (item_id, title) VALUES (1, 'Second Size of Item #1'); 
INSERT INTO sizes (item_id, title) VALUES (2, 'First Size of Item #2'); 
INSERT INTO sizes (item_id, title) VALUES (2, 'Second Size of Item #2'); 

Есть ли способ клона свое предложение со всеми деталями и размерами с помощью одного запроса?

Я попытался решить эту проблему с КТР, вот мой SQL:

WITH tmp_offers AS (
    INSERT INTO offers (title) 
    SELECT title FROM offers WHERE id = 1 
    RETURNING id 
), tmp_items AS (
    INSERT INTO items (offer_id, title) 
    (SELECT (SELECT id FROM tmp_offers), title FROM items WHERE offer_id = 1) 
    RETURNING id 
) 
INSERT INTO sizes (item_id, title) 
(SELECT (SELECT id FROM tmp_items), title FROM sizes WHERE id IN (
    SELECT sizes.id FROM sizes 
    JOIN items ON items.id = sizes.item_id 
    WHERE items.offer_id = 1 
)); 

Но это SQL приводит к ошибке, что я не могу решить:

ОШИБКА: более чем один строка, возвращаемая подзапросом, используемым в качестве выражения

Ваша помощь очень признательна.

P.S. Я использую PostgreSQL 9.5

ответ

3

Это должно работать:

WITH tmp_offers AS (
    INSERT INTO offers (title) 
    SELECT title 
    FROM offers 
    WHERE id = 1 
    RETURNING id 
), tmp_items AS (
    INSERT INTO items (offer_id, title) 
    SELECT o.id, i.title 
    FROM items i 
     cross join tmp_offers o 
    WHERE i.offer_id = 1 
    order by i.id 
    RETURNING items.id 
), numbered_new as (
    select ti.id, 
     row_number() over (order by ti.id) as rn 
    from tmp_items ti 
), numbered_old as (
    select i.id, 
     row_number() over (order by i.id) as rn 
    from items i 
    WHERE i.offer_id = 1 
), item_mapper as (
    select n.id as new_item_id, 
     o.id as old_item_id 
    from numbered_new n 
    join numbered_old o on n.rn = o.rn 
) 
INSERT INTO sizes (item_id, title) 
select im.new_item_id, s.title 
from sizes s 
    join item_mapper im on im.old_item_id = s.item_id; 

онлайн пример: http://rextester.com/RYQUS11008

+0

Спасибо, сэр. Это просто потрясающе и работает точно так, как требуется. –

+0

Думаю, я нашел здесь проблему. Последний запрос выполняет **, где s.id в ** и выбирает идентификатор из таблицы * items *. –

+0

@IM_AG: вы правы. Оказывается, сопоставление старых идентификаторов элементов с идентификаторами новых элементов в таблице размеров не так просто, как я думал. Моя новая версия должна позаботиться об этом. –

0

Вы совсем близко. Это последний вопрос, который нуждается в работе:

WITH tmp_offers AS (
     INSERT INTO offers (title) 
      SELECT title FROM offers WHERE id = 1 
      RETURNING id 
    ), 
    tmp_items AS (
    INSERT INTO items (offer_id, title) 
     SELECT o.id, i.title 
     FROM items i CROSS JOIN 
      (SELECT id FROM tmp_offers) o 
     WHERE i.offer_id = 1 
     RETURNING id, title 
) 
INSERT INTO sizes (item_id, title) 
    SELECT i.id, i.title 
    FROM tmp_items i; 

Основное различие в том, что tmp_items теперь имеет две колонки - и они, как представляется, столбцы, которые вы хотите для этой цели.

+0

Но sizes.title значения неверны. –

 Смежные вопросы

  • Нет связанных вопросов^_^