SQL update with cursors/loops

时间:2015-06-25 10:02:28

标签: sql postgresql

I have 3 SQL tables as follows:

  • Table #1 has column RecipeId
  • Table #2 has column
  • Table #3 has columns RecipeId, AlimentId, Quantity

In all my recipes, I want to replace occurrences of Aliment A by another Aliment B.

Example:

RecipeId  |  AlimentId  |  Quantity 
-----------------------------------
Recipe A  | Aliment A   |  10.
Recipe A  | Aliment B   |   5.
Recipe B  | Aliment C   |   2.
Recipe B  | Aliment B   |   5.
Recipe C  | Aliment A   |   9.

Replacing Aliment A by Aliment B.

Expected output:

RecipeId  |  AlimentId  |  Quantity
-----------------------------------
Recipe A  | Aliment B   |  15.
Recipe B  | Aliment C   |   2.
Recipe B  | Aliment B   |   5.
Recipe C  | Aliment B   |   9.

Another accepted output is to keep records where quantity is equal to 0.

How would you do it in SQL without cursor/loops ? Is there a way to do it with update-set-select-join ? Here, I am afraid that I need something more than a SET...

(I am using postgresql.)

2 个答案:

答案 0 :(得分:0)

如果我理解正确,这就是你需要的

select RecipeId,replace(AlimentId,'Aliment A','Aliment B') as AlimentId,
sum(Quantity) as Quantity 
from #table3
group by RecipeId,replace(AlimentId,'Aliment A','Aliment B') as AlimentId

答案 1 :(得分:0)

CTE中的RETURNING ...子句允许您链接子命令,将它们组合成单个语句。在下面的查询中,这是逐步执行的(可以用更少的步骤完成)

CREATE table ingredients (
        RecipeId text
        ,  AlimentId  text
        ,  Quantity  INTEGER
        );
INSERT INTO ingredients(RecipeId, AlimentId, Quantity) VALUES
  ('RecipeA' , 'AlimentA' ,10 )
, ('RecipeA' , 'AlimentB' ,5 )
, ('RecipeB' , 'AlimentC' ,2 )
, ('RecipeB' , 'AlimentB' ,5 )
, ('RecipeC' , 'AlimentA' ,9 )
        ;
        -- Check the data
SELECT * FROM ingredients
        ;

-- EXPLAIN
        -- The B records that don't have a corresponding A record
WITH mov AS (
        UPDATE ingredients u
        SET AlimentId = 'AlimentB'
        WHERE AlimentId = 'AlimentA'
        AND NOT EXISTS (SELECT * FROM ingredients nx
                WHERE nx.RecipeId = u.RecipeId
                AND nx.AlimentId = 'AlimentB'
                )
        RETURNING u.*
        )
        -- The B records that need to be added to A records AND transformed to B records
, add AS (
        UPDATE ingredients a
        SET AlimentId = 'AlimentB'
                , Quantity = a.Quantity + s.Quantity
        FROM (
                SELECT RecipeId, SUM(Quantity) AS Quantity
                FROM ingredients
                WHERE AlimentId = 'AlimentB'
                GROUP BY RecipeId
                ) s
        WHERE a.AlimentId = 'AlimentA'
        AND a.RecipeId = s.RecipeId
        RETURNING a.*
        )
        -- The B records that have been absorbed by the sum
,       del AS (
        DELETE FROM ingredients d
        WHERE EXISTS ( SELECT * FROM add a WHERE a.RecipeId = d.RecipeId)
        )
        -- construct results
,       tot AS (
        SELECT * FROM ingredients i
        WHERE NOT EXISTS ( SELECT * FROM mov WHERE mov.RecipeId = i.RecipeId)
        AND NOT EXISTS ( SELECT * FROM add WHERE add.RecipeId = i.RecipeId)
        UNION ALL
        SELECT * FROM add
        UNION ALL
        SELECT * FROM mov
        )
        -- report results
SELECT * FROM tot
        ;

        -- check if update/delete succeeded
SELECT * FROM ingredients
        ;