2012-07-09 33 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>)