2012-07-09 31 views
0

我想在多行上执行一个大插入语句,但是递归使得难以构建正确的SQL语句。我相信一个例子会更容易解释。考虑模型:Postgresql中的递归插入子句

 

|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  | 

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

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

伪码(非SQL)应该是这样的: all_cars_and_colors = SELECT * FROM车左外连接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?

+0

如何从car_colors选择模型='豪华'? – wildplasser 2012-07-09 13:59:59

+0

注意:删除了递归查询标记,因为问题不需要递归解决方案。 – wildplasser 2012-07-09 14:17:55

+0

我改进了示例以使其更清晰。基于建议的答案@wildplasser,我相信目前还不清楚表中有几个*项目是否需要更新(不仅仅是豪华型) – mmalmeida 2012-07-09 14:23:51

回答

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' 
     ; 

UPDATE:自requrements似乎已经改变了,这里是一个新的。 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 
     ) 
     ; 
+0

请检查改进的例子:递归来了,我相信,当你有几个模型更新 - 所以明确where子句不是一个选项在这里。 – mmalmeida 2012-07-09 14:25:16

+0

你仍然有一个隐含的连接(old_model <--> new_model),它只能用显式字面值表示(除非旧模型名称是新模型名称的子字符串,并且新名称不存在是) – wildplasser 2012-07-09 15:19:42

+0

你的答案不起作用对于给定的例子:它不会更新豪华版以外的任何其他模型(例如:示例中的标准模型)。 – mmalmeida 2012-07-09 15:35:32

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>)