Postgresql中的Recursive Insert into子句

时间:2012-07-09 13:49:50

标签: sql postgresql

我想在多行上执行一个大的insert语句,但是递归使得构建正确的SQL语句变得很困难。我相信一个例子会让它更容易解释。考虑一下这个模型:


|id|code|Model name     |
|1 |100 |Deluxe         |
|10|100 |Deluxe improved|
|2 |200 |Standard       |
|20|200 |Standard new   |

颜色

|id|Name|
|2 |Red |
|3 |Blue|

car_colors

|id|car_id|color_id|
|3 |1     |2       |
|4 |2     |2       |
|5 |2     |3       |

加入豪华车,然后插入“豪华改进型”车型。这是同一辆车的新版本(相同代码)。不幸的是,John Doe忘了更新car_colors表,所以现在你想通过为每个相同的汽车代码插入相同的颜色来更新该表。

在所考虑的例子中,我们想添加元组“Deluxe Improved,red”(因为Deluxe和deluxe改进了相同的代码,Deluxe可用红色)和元组“标准新,红色”和“标准新,黑色“出于同样的原因。

PSEUDO-CODE(非sql)应该是这样的: all_cars_and_colors = select * from car left outer join car_colors

for each(this_car:all_cars_and_colors){

    if(all_cars_and_colors.color_id does not exist){
        car_colors_to_copy = select * from car inner join car_colors where car.code=this_car.code

        for each(color_to_copy: car_colors_to_copy){
            insert into car_colors(id,car_id,color_id) VALUES (nextval('id_sequence') ,this_car.id,color_to_copy.color_id)
        }

    }
}

如何使用SQL解决这个问题?

2 个答案:

答案 0 :(得分:1)

-- spoiler
INSERT INTO car_colors (car_id, color_id)
SELECT c1.id
        , co.color_id
FROM car c1
JOIN car c0 ON 1=1
JOIN car_colors co ON co.car_id = c0.id
WHERE c1. zname = 'Deluxe improved'
AND c0. zname = 'Deluxe'
        ;

更新:由于要求似乎已经改变,这里是一个新的。 CTE到resque ...

DROP TABLE car ;
CREATE TABLE car
        ( id INTEGER NOT NULL PRIMARY KEY
        , zcode integer NOT NULL
        , zname varchar
        );
INSERT INTO car(id, zcode,zname) VALUES
(1 ,100 , 'Deluxe' )
,(10,100 ,'Deluxe improved' )
,(2 ,200 , 'Standard' )
,(20,200 , 'Standard new' )
        ;

DROP TABLE color ;
CREATE TABLE color
        ( id integer NOT NULL PRIMARY KEY
        , zname varchar
        );

INSERT INTO color(id,zname) VALUES
(2 ,'Red' ) , (3 ,'Blue' )
        ;

DROP TABLE car_colors;
CREATE TABLE car_colors
        ( id SERIAL NOT NULL PRIMARY KEY
        , car_id  integer NOT NULL REFERENCES car (id)
        , color_id  integer NOT NULL REFERENCES color (id)
        , UNIQUE (car_id,color_id)
        )
        ;
INSERT INTO car_colors (car_id, color_id) VALUES
  (1,2) , (2,2) , (2,3)
        ;

WITH carmap AS (
        SELECT c0.id AS orgcar
                , c1.id AS newcar
        FROM car c1
        -- This is an ugly join based on a substring
        JOIN car c0 ON c1.zname ~ c0.zname AND c1.id <> c0.id
        )
INSERT INTO car_colors (car_id, color_id)
SELECT cm.newcar
        , co.color_id
FROM carmap cm
JOIN car_colors co ON co.car_id = cm.orgcar
WHERE NOT EXISTS ( SELECT *
        FROM car_colors nx
        WHERE nx.car_id = cm.newcar
        AND nx.color_id = co.color_id
        )
        ;

答案 1 :(得分:0)

我认为您想要的查询如下:

insert into car_colors(car_id, color_id)
    select <deluxe improved car id>, color_id
    from car_colors
    where car_id = <deluxe car id>

这不处理id,因为这应该在表级别完成。您应该将id列声明为SERIAL列。

如果您担心新行是重复的,请使用:

insert into car_colors(car_id, color_id)
    select <deluxe improved car id>, color_id
    from car_colors cc           
    where car_id = <deluxe car id> and
          color_id not in (select color_id from car_colors where car_id = <deluxe improved car id>)