简体   繁体   中英

How do I make a procedure that sums values stored in nested tables?

I have the following tables:

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
)

Both prod_an_marca in the table marca and prod_an_bod in the table bodega are nested tables of the following type:

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

I've made the following procedure which is supposed to retrieve the ammount of wine produced by any given winery in any given year, the purpose of this is to later insert that ammount into the nested table for production values in the winery, the way this works is through the n:m relationship table (presentacion), which stores a foreign key for (bodega) and a foreign key for (marca) wine.

I'm using a cursor that retrieves the production ammounts for a given year and sums them using SUM in the select, the problem is it sums every single production value that meets the search criteria, this means, it does retrieve the production values for all of the wines belonging to a winery but sums values from every year and not the specified year.

I've tried using GROUP BY to group the sum by year, which stores the proper value for each year stored in the cursor, this could work but I need a way to insert these into the nested table for the wineries' production figures, I'm not sure how I can do this, any help would be appreciated.

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;

The issue is actually much simpler than it might appear from your description. Your query has:

AND nt.ano = ano

As stated in the documentation :

If a SQL statement references a name that belongs to both a column and either a local variable or formal parameter, then the column name takes precedence.

so you are effectively doing:

AND nt.ano = nt.ano

which is more obviously always true. You seem to have avoided the same issue by using slightly different names for id_bod and idbod , possibly accidentally. You can either explicitly state the second reference is the PL/SQL variable by prefixing it with the procedure name:

AND nt.ano = prueba.ano

or change your formal argument name. It's common to use prefixes to avoid this sort of confusion, eg:

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

As mentioned in comments, you should really be using explicit join syntax, and your example doesn't really need an explicit cursor, or a loop (or even any PL/SQL really - though I understand you will be expanding it); you can get the total with just:

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

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM