Problem with PL/SQL anonymous block in an exam - sql

I am working with a code in SQLDeveloper for an exam and I'm having problems with the code. The error shown is
ORA-06502: PL/SQL: numeric or value error: character string buffer too small
ORA-06512: at line 7
00000 - "PL/SQL: numeric or value error%s"
*Cause: An arithmetic, numeric, string, conversion, or constraint error
occurred. For example, this error occurs if an attempt is made to
assign the value NULL to a variable declared NOT NULL, or if an
attempt is made to assign an integer larger than 99 to a variable
declared NUMBER(2).
*Action: Change the data, how it is manipulated, or how it is declared so
that values do not violate constraints.
The code I'm using is this one:
VAR RUT_CLIENTE VARCHAR2(15);
EXEC :RUT_CLIENTE:= '12487147-9';
DECLARE
V_NOMBRE VARCHAR2(75);
V_RUN VARCHAR2(50);
V_RENTA VARCHAR2(12);
V_EST_CIVIL VARCHAR2(40);
BEGIN
SELECT
CLI.NOMBRE_CLI || ' ' || CLI.APPATERNO_CLI || ' ' || CLI.APMATERNO_CLI,
TO_CHAR(CLI.NUMRUT_CLI || '-' || CLI.DVRUT_CLI),
TO_CHAR(CLI.RENTA_CLI, '$999G999G999'),
EST.DESC_ESTCIVIL
INTO V_NOMBRE, V_RUN, V_RENTA, V_EST_CIVIL
FROM CLIENTE CLI JOIN ESTADO_CIVIL EST
ON CLI.ID_ESTCIVIL = EST.ID_ESTCIVIL
WHERE CLI.NUMRUT_CLI || '-' || CLI.DVRUT_CLI = :RUT_CLIENTE;
DBMS_OUTPUT.PUT_LINE('DATOS DEL CLIENTE');
DBMS_OUTPUT.PUT_LINE(' ');
DBMS_OUTPUT.PUT_LINE('----------------');
DBMS_OUTPUT.PUT_LINE(' ');
DBMS_OUTPUT.PUT_LINE('Nombre: ' || V_NOMBRE);
DBMS_OUTPUT.PUT_LINE('RUN: ' || V_RUN);
DBMS_OUTPUT.PUT_LINE('Estado Civil: ' || V_EST_CIVIL);
DBMS_OUTPUT.PUT_LINE('Renta: ' || V_RENTA);
END;
What am I doing wrong? Also, I have to make this block run three times, each time having to enter a different RUT_CLIENTE (the equivalent of the Social Security number in Chile) to show different results, so should I use a loop for that?

You can avoid such errors if you will use define your variables using the types from your cursor:
DECLARE
cursor cur(p_RUT_CLIENTE) is
SELECT
CLI.NOMBRE_CLI || ' ' || CLI.APPATERNO_CLI || ' ' || CLI.APMATERNO_CLI as col_nombre,
TO_CHAR(CLI.NUMRUT_CLI || '-' || CLI.DVRUT_CLI) as col_run,
TO_CHAR(CLI.RENTA_CLI, '$999G999G999') as col_renta,
EST.DESC_ESTCIVIL as col_est_civil
FROM CLIENTE CLI JOIN ESTADO_CIVIL EST
ON CLI.ID_ESTCIVIL = EST.ID_ESTCIVIL
WHERE CLI.NUMRUT_CLI || '-' || CLI.DVRUT_CLI = p_RUT_CLIENTE;
V_NOMBRE cur.col_nombre%type;
V_RUN cur.col_run%type;
V_RENTA cur.col_renta%type;
V_EST_CIVIL cur.est_civil%type;
BEGIN
open cur(:RUT_CLIENTE)
fetch cur into INTO V_NOMBRE, V_RUN, V_RENTA, V_EST_CIVIL;
close cur;
DBMS_OUTPUT.PUT_LINE('DATOS DEL CLIENTE');
DBMS_OUTPUT.PUT_LINE(' ');
DBMS_OUTPUT.PUT_LINE('----------------');
DBMS_OUTPUT.PUT_LINE(' ');
DBMS_OUTPUT.PUT_LINE('Nombre: ' || V_NOMBRE);
DBMS_OUTPUT.PUT_LINE('RUN: ' || V_RUN);
DBMS_OUTPUT.PUT_LINE('Estado Civil: ' || V_EST_CIVIL);
DBMS_OUTPUT.PUT_LINE('Renta: ' || V_RENTA);
END;

Related

How can i turn this pl/sql into a procedure

I had to write this query for an assignement. So we have a database and we are pulling information from it, this is going to work with some back end c# eventually. Is there anything i can do , knowing im going to reuse this, in order to make it better and more adaptable when the day comes when i have to connect it all.
set serveroutput on
DECLARE
LV_DATE HVK_RESERVATION.RESERVATION_START_DATE%TYPE;
LV_SERV VARCHAR(100);
CURSOR LCUR_RES IS
SELECT *
FROM HVK_RESERVATION R
INNER JOIN HVK_PET_RESERVATION PR
ON R.RESERVATION_NUMBER = PR.RES_RESERVATION_NUMBER
INNER JOIN HVK_PET P
ON P.PET_NUMBER = PR.PET_PET_NUMBER
INNER JOIN HVK_OWNER OW
ON OW.OWNER_NUMBER = P.OWN_OWNER_NUMBER
WHERE R.RESERVATION_START_DATE < LV_DATE
AND R.RESERVATION_END_DATE > LV_DATE;
CURSOR LCUR_SERVICE(PET_RES_NUM NUMBER) IS
SELECT *
FROM HVK_SERVICE S
INNER JOIN HVK_PET_RESERVATION_SERVICE PRS
ON PRS.SERV_SERVICE_NUMBER = S.SERVICE_NUMBER
AND PRS.PR_PET_RES_NUMBER = PET_RES_NUM;
BEGIN
LV_DATE := TO_DATE('&logdate', 'yy-mm-dd');
DBMS_OUTPUT.PUT_LINE('Kennel log for ' || '' || LV_DATE);
DBMS_OUTPUT.PUT_LINE('-------------------------------');
FOR I IN LCUR_RES LOOP
DBMS_OUTPUT.PUT_LINE('Run:' || '' || I.RUN_RUN_NUMBER || ' ' ||
'Pet: ' || '' || I.PET_NAME || ' ' ||
I.OWNER_LAST_NAME || ' Pet Reservation: ' || '' ||
I.PET_RES_NUMBER);
DBMS_OUTPUT.PUT_LINE('Reservation start/end ' || ' ' ||
I.RESERVATION_START_DATE || ' ' ||
I.RESERVATION_END_DATE);
DBMS_OUTPUT.PUT('Services : ');
FOR X IN LCUR_SERVICE(I.PET_RES_NUMBER) LOOP
DBMS_OUTPUT.PUT(X.SERVICE_DESCRIPTION || ' ');
END LOOP;
DBMS_OUTPUT.PUT_LINE('');
FOR LREC_LOG IN (SELECT *
FROM HVK_KENNEL_LOG KL
WHERE KL.PR_PET_RES_NUMBER = I.PET_RES_NUMBER
) LOOP
DBMS_OUTPUT.PUT_LINE('Notes: ' || '' ||
LREC_LOG.KENNEL_LOG_SEQUENCE_NUMBER || ' ' ||
'Log Note: ' || '' || LREC_LOG.KENNEL_LOG_NOTES);
END LOOP;
DBMS_OUTPUT.PUT_LINE(' ');
END LOOP;
END;
It it supposed to output the run number , reservation number , pet name , and any relate notes.
you can replace DECLARE with CREATE OR REPLACE PROCEDURE my_proc(in_logdate in date) IS.
in that case my_proc will be the name of your procedure.
you should also use a parameter instead of &logdate
so e.g. parameter name in_logdate of type date
...
LV_DATE := in_logdate;
...

error when executing a varchar2 in a procedure

I have a varchar2 with an INSERT and I want to execute it in a procedure I try to do it with an execute but this happens:
EXECUTE IMMEDIATE sql_str;
Error:
ERROR at line 1:
ORA-00911: invalid character
ORA-06512: at "SYS.INSERT_MOVIMIENTOS", line 47
ORA-06512: at line 1
Varchar2 carries an insert that is this and works if I paste it but when executing it in the procedure something of the procedure fails.
INSERT INTO MOVIMIENTOS (COD_BANCO, COD_SUCUR, NUM_CTA, FECHA_MOV, TIPO_MOV, IMPORTE) VALUES (2000, 2000, 0, '11/11/08', 'I', 500);
My procedure
CREATE OR REPLACE PROCEDURE INSERT_MOVIMIENTOS (
INSERTMOV_COD_BANCO IN NUMBER,
INSERTMOV_COD_SUCUR IN NUMBER,
INSERTMOV_NUM_CTA IN NUMBER,
INSERTMOV_FECHA_MOV IN DATE,
INSERTMOV_TIPO_MOV IN CHAR,
INSERTMOV_IMPORTE IN NUMBER
)
IS
sql_str VARCHAR2(500) := 'INSERT INTO MOVIMIENTOS (';
movimiento movimientos_typ;
BEGIN
movimiento := movimientos_typ(
INSERTMOV_COD_BANCO,
INSERTMOV_COD_SUCUR,
INSERTMOV_NUM_CTA,
INSERTMOV_FECHA_MOV,
INSERTMOV_TIPO_MOV,
INSERTMOV_IMPORTE
);
IF movimiento.getCOD_BANCO() != 0 THEN
sql_str := sql_str || 'COD_BANCO, COD_SUCUR, NUM_CTA, FECHA_MOV, TIPO_MOV, IMPORTE) VALUES (' ||
movimiento.getCOD_BANCO() || ', ' ||
movimiento.getCOD_SUCUR() || ', ' ||
movimiento.getNUM_CTA() || ', ''' ||
movimiento.getFECHA_MOV() || ''', ''' ||
movimiento.getTIPO_MOV() || ''', ' ||
movimiento.getIMPORTE() || ');';
ELSE
sql_str := sql_str || 'COD_SUCUR, NUM_CTA, FECHA_MOV, TIPO_MOV, IMPORTE) VALUES (' ||
movimiento.getCOD_SUCUR() || ', ' ||
movimiento.getNUM_CTA() || ', ''' ||
movimiento.getFECHA_MOV() || ''', ''' ||
movimiento.getTIPO_MOV() || ''', ' ||
movimiento.getIMPORTE() || ');';
END IF;
DBMS_OUTPUT.PUT_LINE('////////////////////////////////////////');
DBMS_OUTPUT.PUT_LINE('CONSULTA: ' || sql_str);
DBMS_OUTPUT.PUT_LINE('////////////////////////////////////////');
DBMS_OUTPUT.PUT_LINE('DATOS INTRODUCIDOS: ');
movimiento.display;
DBMS_OUTPUT.PUT_LINE('////////////////////////////////////////');
EXECUTE IMMEDIATE sql_str;
DBMS_OUTPUT.PUT_LINE('FUNCION REALIZADA CON EXITO');
END;
/
Donot end with the semicolon ; in your query string.
movimiento.getIMPORTE() || ')';
The error is just because of it.
by the way, you should be using bind variables. Dynamically constructing the values this way is vulnerable to SQL Injection.

Postgres Type of Parameter does not match

I am having an odd problem with Postgres (10.5). I have a function, generate_unique_name which takes in three text values. It works fine; however, calling this function seems to be an issue. When I call the function using:
SELECT generate_unique_name('basic', 'seeds', 'project=' || 2)
It works without issue. I can make the same call several times. Now, when I try the same call, but change the second parameter as below:
SELECT generate_unique_name('basic', 'queue', 'project=' || 2)
Then it seems to fail with the error:
ERROR: type of parameter 9 (text) does not match that when preparing
the plan (character varying) CONTEXT: PL/pgSQL function
generate_unique_name(text,text,text) line 12 at assignment SQL state:
42804
I have tried changing the query to:
SELECT generate_unique_name('basic'::text, 'queue'::text, ('project=' || 2)::text)
But this also fails. If I then kill the connection to postgres DB, and create a new one, and instead start with the second query, it now works, but the first stops functioning.
It seems like postgres decides to stop treating the parameters as text part way through, for no apparent reason. Am I missing something?
EDIT: Code for generate_unique_name
CREATE OR REPLACE FUNCTION public.generate_unique_name(
proposed_name text,
table_name text,
condition text)
RETURNS text
LANGUAGE 'plpgsql'
COST 100
VOLATILE
AS $BODY$
DECLARE
unique_name text;
name_counter integer;
r record;
names_to_check text[];
BEGIN
unique_name = proposed_name;
name_counter = 0;
FOR r IN EXECUTE 'SELECT name FROM ' || table_name || ' WHERE ' || condition LOOP
names_to_check = array_append(names_to_check, r.name::text);
END LOOP;
WHILE unique_name = ANY(names_to_check) LOOP
name_counter = name_counter + 1;
unique_name = proposed_name || ' (' || name_counter || ')';
END LOOP;
RETURN unique_name;
END;
$BODY$;
My guess is there's a value in the name column of the queue table that causes an issue with
names_to_check = array_append(names_to_check, r.name::text)
As Joe mentioned, the issue was with the array_append, which I could not figure out a way to fix. Instead, the generate_unique_names functions was changed to just query the DB continuously.
CREATE OR REPLACE FUNCTION generate_unique_name (proposed_name text, table_name text, condition text) RETURNS text AS
$BODY$
DECLARE
unique_name text;
name_counter integer;
not_unique boolean;
BEGIN
unique_name = proposed_name;
name_counter = 0;
EXECUTE 'SELECT COUNT(*)!=0 FROM ' || table_name || ' WHERE ' || condition || ' AND name = ''' || unique_name || '''' INTO not_unique;
WHILE not_unique LOOP
name_counter = name_counter + 1;
unique_name = proposed_name || ' (' || name_counter || ')';
EXECUTE 'SELECT COUNT(*)!=0 FROM ' || table_name || ' WHERE ' || condition || ' AND name = ''' || unique_name || '''' INTO not_unique;
END LOOP;
RETURN unique_name;
END;
$BODY$ LANGUAGE plpgsql;

FRM-40735: When button pressed trigger raised unhandled exception ORA-06502

if :entete.carto = 'O' then
declare
c_criteres varchar2(240);
BEGIN
go_item(:ENTETE.CURRENT_ITEM_PRECEDENT);
IF :ENTETE.LOX_BE='PTV' THEN
:global.type_lancement := 'GEOCOD';
c_criteres := '-jar '|| :entete.empl_jar||'geocodeur.jar '
|| :entete.c_user || ' '
|| :entete.c_passe || ' '
|| :global.connection_string || ' '
|| '1 ' -- ecrire dans un fichier en sortie
|| '1 ' -- debug
|| '1' /*geocod cf*/ || ' '
|| :global.chemin_cr || ' '
|| :global.utilisateur;
lancer_executable('javaw',:entete.c_user,:entete.c_passe,
:entete.c_noeud,:entete.c_os,'1',c_criteres);
END IF;
enter_query;
END;
end if;
can someone advise about the reason for such an error?
I am new to oracle forms and need to figure out why this issue is occuring in order to resolve it.
thank you
Usually this error is because you are trying to assign a value to a variable or field that is not to big enough. Example
v_name VARCHAR2(5);
After you try to:
v_name := 'ABCDEFGHIJK';
The variable's length is 5 and you try to assign a string with 10 characters.
Hope it helps.

Reading rows from an Oracle Object that is a table of other objects

Forgive me, this is my first attempt at an Oracle Package, so I am hopefully missing something simple.
EDIT I sorted it...
Need to reference the actual declaring sub-type, as such:
FOR j in outvar(i).tbl_ORDER_TENDERS.first..outvar(i).tbl_ORDER_TENDERS.last LOOP
DBMS_OUTPUT.PUT_LINE('tender record : '
|| to_char(outvar(i).tbl_ORDER_TENDERS(j).TENDER_AMT) || ' '
I created several a couple new Oracle Types, that will hold row data from my DB, as such:
create or replace
TYPE ORDERS_TABLE
IS TABLE OF ORDER_HEADER;
And that refers to my other type:
create or replace
TYPE ORDER_HEADER FORCE
AS OBJECT (
TRANSACTION_NUMBER VARCHAR2(20),
LOCATION_NUMBER VARCHAR2(10),
TERMINAL_NAME VARCHAR2(25),
START_DATETIME TIMESTAMP(6),
GROSS_SALES_AMOUNT NUMBER(20,0),
NET_SALES_AMOUNT NUMBER(20,0),
SAVINGS_AMOUNT NUMBER(20,0),
SAVINGS_PRECISION NUMBER(6,0),
TOTAL_TAX NUMBER(20,0),
CUSTOMER_IDENTIFIER VARCHAR2(50),
tbl_ORDER_LINES ORDER_LINES,
tbl_ORDER_TENDERS ORDER_TENDERS,
TBL_ORDER_REBATES ORDER_REBATES
);
And for example, take the ORDER_TENDERS type:
create or replace
TYPE ORDER_TENDERS FORCE
AS TABLE OF ORDER_TENDER;
Which contains the rows of tender data:
create or replace
TYPE ORDER_TENDER AS OBJECT
(
TENDER_LINE_ID NUMBER(20,0),
TENDER_CODE VARCHAR2(10),
TENDER_AMT NUMBER(20,0),
UNENCODED_ACCOUNT_NUMBER VARCHAR2(25)
);
So my package I think is working, where I can fill these objects (verified the HEADER stuff working at least.) But I'm not sure how to test/debug/view the results when I call this package to see if I'm getting the ORDER_TENDER/ORDER_TENDERS data...
For example, this works fine:
declare
invar varchar2(5);
outvar ORDERS_TABLE;
O_ORDER_TENDERS ORDER_TENDERS;
O_ORDER_TENDER ORDER_TENDER;
begin
sales_trickler.GetSales(invar, outvar);
FOR i in 1..outvar.COUNT LOOP
DBMS_OUTPUT.PUT_LINE(' record : '
|| to_char(outvar(i).TRANSACTION_NUMBER) || ' '
|| to_char(outvar(i).LOCATION_NUMBER) || ' '
|| to_char(outvar(i).TERMINAL_NAME) || ' '
|| to_char(outvar(i).CUSTOMER_IDENTIFIER));
END LOOP;
end;
But how do I see the ORDER_TENDERS/ORDER_TENDER data?
I tried putting this extra FOR LOOP in, but it doesn't like how I'm referring to ORDER_TENDER(S)...
declare
invar varchar2(5);
outvar ORDERS_TABLE;
O_ORDER_TENDERS ORDER_TENDERS;
O_ORDER_TENDER ORDER_TENDER;
begin
sales_trickler.GetSales(invar, outvar);
FOR i in 1..outvar.COUNT LOOP
DBMS_OUTPUT.PUT_LINE(' record : '
|| to_char(outvar(i).TRANSACTION_NUMBER) || ' '
|| to_char(outvar(i).LOCATION_NUMBER) || ' '
|| to_char(outvar(i).TERMINAL_NAME) || ' '
|| to_char(outvar(i).CUSTOMER_IDENTIFIER));
FOR j in 1..outvar(i).O_ORDER_TENDERS.COUNT LOOP
DBMS_OUTPUT.PUT_LINE('tender record : '
|| to_char(O_ORDER_TENDERS(j).TENDER_AMT) || ' '
);
END LOOP;
END LOOP;
end;
I tried relating to outvar(i).ORDER_TENDERS but that didn't work either... any ideas?
The problem was in the calling code, I shouldn't refer to new instances of the sub-objects, I should refer to them 'as they live' in the original parameter being passed, as such:
tbl_ORDER_LINES ORDER_LINES,
tbl_ORDER_TENDERS ORDER_TENDERS,
TBL_ORDER_REBATES ORDER_REBATES
Here's the actual statement:
declare
invar varchar2(5);
outvar ORDERS_TABLE;
begin
sales_trickler.GetSales(invar, outvar);
FOR i in 1..outvar.COUNT LOOP
DBMS_OUTPUT.PUT_LINE(' record : '
|| to_char(outvar(i).TRANSACTION_NUMBER) || ' '
|| to_char(outvar(i).LOCATION_NUMBER) || ' '
|| to_char(outvar(i).TERMINAL_NAME) || ' '
|| to_char(outvar(i).CUSTOMER_IDENTIFIER));
FOR j in outvar(i).tbl_ORDER_TENDERS.first..outvar(i).tbl_ORDER_TENDERS.last LOOP
DBMS_OUTPUT.PUT_LINE('tender record : '
|| to_char(outvar(i).tbl_ORDER_TENDERS(j).TENDER_AMT) || ' '
);
END LOOP;
--lines
FOR j in outvar(i).tbl_ORDER_LINES.first..outvar(i).tbl_ORDER_LINES.last LOOP
DBMS_OUTPUT.PUT_LINE('line record : '
|| to_char(outvar(i).tbl_ORDER_LINES(j).SKU) || ' '
);
END LOOP;
END LOOP;
end;