Reputation: 55
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;
Upvotes: 0
Views: 226
Reputation: 191570
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, e.g.:
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;
/
Upvotes: 1