如何制作一个对嵌套表中存储的值求和的过程?

时间:2018-12-18 16:48:07

标签: sql database oracle plsql

我有下表:

CREATE TABLE bodega (  --winery
   id_bod                   INTEGER NOT NULL,
   prod_an_bod              nt_tipo_valor , --annual production
 )

CREATE TABLE marca ( --wine
id_marca                INTEGER NOT NULL,   
prod_an_marca           nt_tipo_valor ,  --annual production
)

CREATE TABLE presentacion (  --n:m relation table
id_pres                  INTEGER NOT NULL,
bodega_fk                INTEGER NOT NULL,
marca_fk                 INTEGER NOT NULL
)

表marca中的prod_an_marca和表bodega中的prod_an_bod都是以下类型的嵌套表:

CREATE OR REPLACE TYPE tipo_valor AS OBJECT (
ano        DATE, --year
cantidad   INTEGER --ammount of wine produced
)

我已经执行了以下过程,该过程应该检索任何给定酿酒厂在任何给定年份生产的葡萄酒数量,其目的是稍后将该数量插入嵌套表中,以获取该酿酒厂的生产价值,这种工作方式是通过n:m关系表(presentacion)进行的,该表存储了(bodega)的外键和(marca)葡萄酒的外键。

我正在使用一个游标,该游标检索给定年份的生产量,并在选择中使用SUM求和,问题是它求和了满足搜索条件的每个单个生产值,这意味着它确实检索了生产属于某个酒庄的所有葡萄酒的价值,但每年的总和而不是指定年份的价值。

我尝试使用GROUP BY按年份对总和进行分组,该总和将存储在游标中的每年的正确值存储起来,这可能有效,但是我需要一种方法将其插入嵌套表中以供酿酒厂生产数字,我不确定如何做到这一点,我们将不胜感激。

Create or replace procedure prueba(idbod INTEGER, ano DATE)
CURSOR prodbod IS
SELECT 
sum(nt.cantidad)    
FROM    bodega b,
presentacion p,
marca m,     
TABLE(m.prod_an_marca) nt
WHERE m.id_marca = p.marca_fk   
AND b.id_bod = p.bodega_fk 
AND b.id_bod = idbod
AND nt.ano = ano;
tempvar INTEGER; 
BEGIN
OPEN prodbod;
    LOOP
        FETCH prodbod INTO tempvar;
        EXIT WHEN prodbod%NOTFOUND;
        DBMS_OUTPUT.PUT_LINE('tempvar:'||to_char(tempvar));
    END LOOP;
CLOSE prodbod; 
END;

1 个答案:

答案 0 :(得分:1)

问题实际上比您的描述中出现的要简单得多。您的查询有:

AND nt.ano = ano

As stated in the documentation

  

如果SQL语句引用的名称既属于列又属于局部变量或形式参数,则该列名称优先。

所以您实际上是在做:

AND nt.ano = nt.ano

这显然总是正确的。您似乎通过为id_bodidbod使用稍微不同的名称来避免了相同的问题,这可能是偶然的。您可以通过在过程名称前添加前缀来明确声明第二个引用是PL / SQL变量:

AND nt.ano = prueba.ano

或更改您的正式参数名称。通常使用前缀来避免这种混淆,例如:

Create or replace procedure prueba(p_id_bod INTEGER, p_ano DATE) as
...
AND b.id_bod = p_id_bod
AND nt.ano = p_ano;
...

如评论中所述,您实际上应该使用显式联接语法,并且您的示例确实不需要显式游标或循环(甚至不需要任何PL / SQL,尽管我知道您将对其进行扩展) ;您可以通过以下方式获得总数:

Create or replace procedure prueba(p_idbod INTEGER, p_ano DATE) as
  tempvar INTEGER;
BEGIN
  SELECT sum(nt.cantidad)
  INTO tempvar
  FROM bodega b
  JOIN presentacion p on p.bodega_fk = b.id_bod
  JOIN marca m on m.id_marca = p.marca_fk
  CROSS JOIN TABLE(m.prod_an_marca) nt
  WHERE b.id_bod = p_id_bod
  AND nt.ano = p_ano;

  DBMS_OUTPUT.PUT_LINE('tempvar:'||to_char(tempvar));
END;
/