I define a new type in sql oracle and define a static procedure.
CREATE OR REPLACE TYPE address AS OBJECT(
house_no VARCHAR2 (10),
street VARCHAR2 (30),
city VARCHAR2 (20),
state VARCHAR2 (10),
pincode VARCHAR2 (10),
STATIC PROCEDURE new_address (house_no VARCHAR2,
street VARCHAR2,
city VARCHAR2,
state VARCHAR2,
pincode VARCHAR2)
);
CREATE OR REPLACE TYPE BODY address
AS
STATIC PROCEDURE new_address (house_no VARCHAR2,
street VARCHAR2,
city VARCHAR2,
state VARCHAR2,
pincode VARCHAR2)
IS
sqlstmt VARCHAR (100);
BEGIN
sqlstmt :=
'insert into university.user_address values(address(:name, :name, :name, :name, :name, :name))';
EXECUTE IMMEDIATE sqlstmt
USING house_no,
street,
city,
state,
pincode;
END;
END;
When I called the function user_address it shows error: not all variables bound.
CREATE TABLE user_address OF address
begin
UNIVERSITY.address.new_address('123', 'nazar', 'isfahan','isfahan','9893');
END;
I changed implementing like this (edit sqlstmt with numbers) , but it shows error again.
sqlstmt :=
'insert into university.user_address values(address(:1, :2, :3, :4, :5, :6))';
How do I fix it?
Below line have 6 bind variables where as execute immediate only have 5.
sqlstmt :=
'insert into university.user_address values(address(:name, :name, :name, :name, :name, :name))';
Related
CREATE TABLE Docente
(
opcion varchar2(10),
id_Docente NUMBER,
nombre VARCHAR2(30),
apellido VARCHAR2(30),
cedula NUMBER,
titulo VARCHAR2(100),
observaciones VARCHAR2(200),
estado VARCHAR2(10),
mensaje varchar2(50) NULL,
CONSTRAINT PK_Docente PRIMARY KEY (id_Docente)
);
CREATE OR REPLACE PROCEDURE sp_crud_docente(
p_opcion varchar2,
p_id_Docente NUMBER,
p_nombre VARCHAR2,
p_apellido VARCHAR2,
p_cedula NUMBER,
p_titulo VARCHAR2,
p_observaciones VARCHAR2,
p_estado VARCHAR2,
p_mensaje out varchar2)
as
v_valor int;
v_row Docente%rowtype;
begin
if (p_opcion = 'I') then
begin
Select MAX(id_Docente)+ 1 into v_valor from Docente;
if v_valor is null then
v_valor := 1;
p_mensaje:= 'Registro inserted...';
DBMS_OUTPUT.PUT_LINE(p_mensaje);
insert into Docente
values (p_opcion,v_valor,p_id_Docente,p_nombre,p_apellido,p_cedula,p_titulo,p_observaciones,p_estado);
end if;
end;
else if (p_opcion = 'U') then
update Docente set opcion=p_opcion,
id_Docente=p_id_Docente,
nombre=p_nombre,
apellido=p_apellido,
cedula=p_cedula,
titulo=p_titulo,
observaciones=p_observaciones,
estado=p_estado
where id_Docente=p_id_Docente;
p_mensaje:= 'Registro updated...';
DBMS_OUTPUT.PUT_LINE(p_mensaje);
else if (p_opcion = 'S') then
begin
Select
opcion,
id_Docente,
nombre,
apellido,
cedula,
titulo,
observaciones,
estado,
mensaje
into v_row
from Docente;
p_mensaje := ('Ok');
DBMS_OUTPUT.PUT_LINE(p_mensaje||' --> '||v_row.opcion||'|'||v_row.id_Docente||'|'||v_row.nombre||'|'||v_row.apellido||'|'||v_row.cedula||'|'||v_row.titulo||'|'||v_row.observaciones||'|'||v_row.estado||'|'||v_row.mensaje);
end;
else if (p_opcion = 'D') then
Delete from Docente where id_Docente=p_id_Docente;
p_mensaje := ('Proceso ejecutado correctamente');
DBMS_OUTPUT.PUT_LINE(p_mensaje);
commit;
end if;
end if;
end if;
end if;
EXCEPTION
WHEN OTHERS then
p_mensaje := ('ERROR. No se pudo ejecutar el proceso');
rollback;
end;
Take out the length of the incoming parameters:
create or replace procedure sp_crud_docente (
p_opcion varchar2,
p_id_Docente NUMBER,
p_nombre VARCHAR2,
p_apellido VARCHAR2,
p_cedula NUMBER,
p_titulo VARCHAR2,
p_observaciones VARCHAR2,
p_estado VARCHAR2,
p_mensaje out varchar2)
See 8.7.1 Formal and Actual Subprogram Parameters section of the 19c manual "Database PL/SQL Language Reference"
Bobby
Apart from the fact that varchar2 parameters can't have size, this is practically unsolvable without you posting the docente table description.
Bad habits kick; you're wrongly relying on the fact that you know what you're doing, but it turns out you don't.
I can't figure out how many nor which columns docente contains, and in which order.
insert into docente should explicitly mention all columns you're inserting into, one-by-one. Code you wrote suggests that table contains 9 columns (opcion, id_docente, nombre, apellido, cedula, titulo, observaciones, estado).
update, on the other hand, updates only 6 of them (nombre, apellido, cedula, tutlo, observaciones, estado) which doesn't collide with insert; it is OK if you don't update all columns.
However, p_opcion = 'S' selects only 7 columns into v_row which is declared as docente%rowtype. Out of those 7 columns, I believe you "forgot" a comma between id_docente and nombre - those are two columns, it's not that nombre is id_docente's alias, right? Suppose it is 8 columns that are selected after all. Now, that collides with number of columns you used in insert (9 of them). If you're selecting into %rowtype, you must select ALL columns in EXACT ORDER.
I suggest you review code you wrote, pay attention about what I said and fix those errors.
I am trying to use dynamic SQL to insert values into my table. But I am struggling with it! This is my table
CREATE TABLE CARS
(
ID INTEGER PRIMARY KEY,
Manufacturer VARCHAR2(1000),
Model VARCHAR2(1000),
Year INTEGER NOT NULL,
Category VARCHAR2(1000) NOT NULL,
Mileage NUMBER,
FuelType VARCHAR2(1000),
EngineVolume NUMBER,
DriveWheels VARCHAR2(1000),
GearBox VARCHAR2(1000),
Doors VARCHAR2(1000),
Wheel VARCHAR2(1000),
Color VARCHAR2(1000),
InteriorColor VARCHAR2(1000),
VIN VARCHAR2(1000),
LeatherInterior VARCHAR2(1000) NOT NULL,
Price VARCHAR2(1000) NOT NULL,
Clearence VARCHAR2(1000) NOT NULL
)
And I have created a trigger that will increment the id column automatically.
CREATE SEQUENCE cars_seq START WITH 93100;
CREATE OR REPLACE TRIGGER cars_id_inc
BEFORE INSERT ON cars FOR EACH ROW
BEGIN
:NEW.ID := CARS_SEQ.nextval;
END;
Then I have created a procedure that will insert values into the cars table.
CREATE OR REPLACE PROCEDURE insert_all_cars (p_values VARCHAR2) IS
v_stmt VARCHAR2(10000);
BEGIN
v_stmt := 'INSERT INTO CARS ' || ' VALUES ' || p_values;
EXECUTE IMMEDIATE v_stmt;
END;
When I am trying to insert values to the cars table using a procedure like this:
DECLARE
p_values VARCHAR2 := '(''new_manufacturer'', ''new_model'', ' || '2000' || ' ,''new_category'', ' || '2000' ||' ,''new_fueltype'', ' || '3.0' ||
' ,''new_drivewheels'',''new_gearbox'',''new_doors'',''new_wheel'',''new_color'',
''new_interior_color'',''new_vin'',''new_leather_interior'',''new_price'',''new_clearence'')';
BEGIN
insert_all_cars(p_values);
END;
I am getting this kind of error:
Error starting at line : 60 in command -
DECLARE
p_values VARCHAR2 := '(''new_manufacturer'', ''new_model'', ' || '2000' || ' ,''new_category'', ' || '2000' ||' ,''new_fueltype'', ' || '3.0' ||
' ,''new_drivewheels'',''new_gearbox'',''new_doors'',''new_wheel'',''new_color'',
''new_interior_color'',''new_vin'',''new_leather_interior'',''new_price'',''new_clearence'')';
BEGIN
insert_all_cars(p_values);
END;
Error report -
ORA-06550: line 2, column 14:
PLS-00215: String length constraints must be in range (1 .. 32767)
06550. 00000 - "line %s, column %s:\n%s"
*Cause: Usually a PL/SQL compilation error.
*Action:
Also tried to put numbers without quotes got the same kind error.
How I can fix it?
You didn't define the length of p_values in your anonymous pl/sql block. But why use dynamic sql? This is a really poor use case for it. Why not this?
create or replace procedure insert_all_cars (
p_manufacturer VARCHAR2,
p_model VARCHAR2,
p_year INTEGER,
p_category VARCHAR2,
p_mileage NUMBER,
p_fueltype VARCHAR2,
p_enginevolume NUMBER,
p_drivewheels VARCHAR2,
p_gearbox VARCHAR2,
p_doors VARCHAR2,
p_wheel VARCHAR2,
p_color VARCHAR2,
p_interiorcolor VARCHAR2,
p_vin VARCHAR2,
p_leatherinterior VARCHAR2,
p_price VARCHAR2,
p_clearence VARCHAR2) is
begin
insert into cars (
Manufacturer,
Model,
Year,
Category,
Mileage,
FuelType,
EngineVolume,
DriveWheels,
GearBox,
Doors,
Wheel,
Color,
InteriorColor,
VIN,
LeatherInterior,
Price,
Clearence )
values (
p_manufacturer,
p_model,
p_year,
p_category,
p_mileage,
p_fueltype,
p_enginevolume,
p_drivewheels,
p_gearbox,
p_doors,
p_wheel,
p_color,
p_interiorcolor,
p_vin,
p_leatherinterior,
p_price,
p_clearence );
end;
/
And then this:
begin
insert_all_cars (
p_manufacturer => 'new_manufacturer',
p_model => 'new_model',
p_year => 2000,
p_category => 'new_category',
p_mileage => 2000,
p_fueltype => 'new_fueltype',
p_enginevolume => 3.0,
p_drivewheels => 'new_drivewheels',
p_gearbox => 'new_gearbox',
p_doors => 'new_doors',
p_wheel => 'new_wheel',
p_color => 'new_color',
p_interiorcolor => 'new_interior_color',
p_vin => 'new_vin',
p_leatherinterior => 'new_leather_interior',
p_price => 'new_price',
p_clearence => 'new_clearence'
);
commit;
end;
/
I want to know if there exists something like Reflection API in PL/SQL or not.
I have a table like
create table my_table (
id number,
value1 number,
value2 number,
value3 number,
value4 number,
value5 number);
And I have a variable as
rec as my_table%rowtype
... fill rec
insert into my_table values rec;
is there any way I can populate rec field dynamically by its name.
I mean I know the index (in this case something between 1 and 5), so I want to set 'value'||index to something.
As in my real case the last index is much more than 5, using a set of if/elsif is not proper. By the way number of fields is increased in long term (for example value6, value7 ma be added next year and so on, so I wan to write some kind of code not to be changed on every new column).
You can access variables in a program using dynamic SQL only if they are available globally. If you declare you record in the spec you can build utility functions that will use EXECUTE IMMEDIATE to build a small PL/SQL block to set the value. Here is a simple example of what you are looking for. Notice you can overload the set procedure to keep your datatypes intact.
CREATE TABLE my_table (
value1 NUMBER,
value2 VARCHAR2(100),
value3 DATE);
CREATE OR REPLACE PACKAGE pkg_my_table IS
my_table_rec my_table%ROWTYPE;
FUNCTION build_statement(i_record IN VARCHAR2,
i_field IN VARCHAR2) RETURN VARCHAR2;
PROCEDURE set_value(i_record IN VARCHAR2,
i_field IN VARCHAR2,
i_value IN VARCHAR2);
PROCEDURE set_value(i_record IN VARCHAR2,
i_field IN VARCHAR2,
i_value IN NUMBER);
PROCEDURE set_value(i_record IN VARCHAR2,
i_field IN VARCHAR2,
i_value IN DATE);
PROCEDURE insert_a_row;
END pkg_my_table;
/
CREATE OR REPLACE PACKAGE BODY pkg_my_table IS
FUNCTION build_statement(i_record IN VARCHAR2,
i_field IN VARCHAR2) RETURN VARCHAR2 IS
BEGIN
RETURN 'BEGIN ' || lower($$PLSQL_UNIT) || '.' || i_record || '.' || i_field || ' := :x; END;';
END build_statement;
PROCEDURE set_value(i_record IN VARCHAR2,
i_field IN VARCHAR2,
i_value IN VARCHAR2) IS
BEGIN
EXECUTE IMMEDIATE build_statement(i_record => i_record,
i_field => i_field)
USING i_value;
END set_value;
PROCEDURE set_value(i_record IN VARCHAR2,
i_field IN VARCHAR2,
i_value IN NUMBER) IS
BEGIN
EXECUTE IMMEDIATE build_statement(i_record => i_record,
i_field => i_field)
USING i_value;
END set_value;
PROCEDURE set_value(i_record IN VARCHAR2,
i_field IN VARCHAR2,
i_value IN DATE) IS
BEGIN
EXECUTE IMMEDIATE build_statement(i_record => i_record,
i_field => i_field)
USING i_value;
END set_value;
PROCEDURE insert_a_row IS
BEGIN
my_table_rec := NULL;
set_value(i_record => 'my_table_rec',
i_field => 'value1',
i_value => 42);
set_value(i_record => 'my_table_rec',
i_field => 'value2',
i_value => 'forty-two');
set_value(i_record => 'my_table_rec',
i_field => 'value3',
i_value => to_date('1/1/1942',
'mm/dd/yyyy'));
INSERT INTO my_table
VALUES my_table_rec;
END insert_a_row;
END pkg_my_table;
/
BEGIN
pkg_my_table.insert_a_row;
END;
/
SELECT *
FROM my_table;
-- 42 forty-two 1/1/1942
Beware globals: you need to reset them correctly before using them again or you might get data carried over from previous invocations. Setting an entire record type variable to NULL will reset all the underlying fields (handy).
You will also be prone to ORA-04068: existing state of packages has been discarded errors should you compile PL/SQL with globals where there are active sessions referencing your code. Generally this is not a problem, but it is a behavioral difference.
Here is my procedure:
CREATE OR REPLACE PACKAGE shop_query_pkg IS
PROCEDURE shop_info_pp
(p_id IN bb_shopper.idshopper%TYPE,
p_firstname OUT bb_shopper.firstname%TYPE,
p_city OUT bb_shopper.city%TYPE,
p_state OUT bb_shopper.state%TYPE,
p_phone OUT bb_shopper.phone%TYPE,
p_email OUT bb_shopper.email%TYPE);
PROCEDURE shop_info_pp
(p_id IN bb_shopper.lastname%TYPE,
p_firstname OUT bb_shopper.firstname%TYPE,
p_city OUT bb_shopper.city%TYPE,
p_state OUT bb_shopper.state%TYPE,
p_phone OUT bb_shopper.phone%TYPE,
p_email OUT bb_shopper.email%TYPE);
END;
/
CREATE OR REPLACE PACKAGE BODY shop_query_pkg IS
PROCEDURE shop_info_pp
(p_id IN bb_shopper.idshopper%TYPE,
p_firstname OUT bb_shopper.firstname%TYPE,
p_city OUT bb_shopper.city%TYPE,
p_state OUT bb_shopper.state%TYPE,
p_phone OUT bb_shopper.phone%TYPE,
p_email OUT bb_shopper.email%TYPE)
IS
BEGIN
SELECT firstname, city, state, phone, email
INTO p_firstname, p_city, p_state, p_phone, p_email
FROM bb_shopper
WHERE idshopper = p_id;
EXCEPTION
WHEN NO_DATA_FOUND THEN
DBMS_OUTPUT.PUT_LINE('ID does not exist');
END;
PROCEDURE shop_info_pp
(p_id IN bb_shopper.lastname%TYPE,
p_firstname OUT bb_shopper.firstname%TYPE,
p_city OUT bb_shopper.city%TYPE,
p_state OUT bb_shopper.state%TYPE,
p_phone OUT bb_shopper.phone%TYPE,
p_email OUT bb_shopper.email%TYPE)
IS
BEGIN
SELECT firstname, city, state, phone, email
INTO p_firstname, p_city, p_state, p_phone, p_email
FROM bb_shopper
WHERE lastname = p_id;
EXCEPTION
WHEN NO_DATA_FOUND THEN
DBMS_OUTPUT.PUT_LINE('Last name does not exist');
END;
END;
However when I try to execute my procedure using this code:
VARIABLE g_fname VARCHAR2
VARIABLE g_city VARCHAR2
VARIABLE g_state VARCHAR2
VARIABLE g_phone VARCHAR2
VARIABLE g_email VARCHAR2
EXECUTE shop_query_pkg.shop_info_pp(23, :g_fname, :g_city, :g_state, :g_phone, :g_email);
PRINT :g_fname
PRINT :g_city
PRINT :g_state
PRINT :g_phone
PRINT :g_email
I get this error message:
BEGIN shop_query_pkg.shop_info_pp(23, :g_fname, :g_city, :g_state, :g_phone, :g_email); END;
*
ERROR at line 1:
ORA-06502: PL/SQL: numeric or value error
ORA-06512: at "S36.SHOP_QUERY_PKG", line 11
ORA-06512: at line 1
I think it something wrong with my select statement, but I keep checking it and I can't figure out what's wrong with it.
Here is the DESC bb_shopper:
Name Null? Type
IDSHOPPER NOT NULL NUMBER(4)
FIRSTNAME VARCHAR2(15)
LASTNAME VARCHAR2(20)
ADDRESS VARCHAR2(40)
CITY VARCHAR2(20)
STATE CHAR(2)
ZIPCODE VARCHAR2(15)
PHONE VARCHAR2(10)
FAX VARCHAR2(10)
EMAIL VARCHAR2(25)
USERNAME VARCHAR2(8)
PASSWORD VARCHAR2(8)
COOKIE NUMBER(4)
DTENTERED DATE
PROVINCE VARCHAR2(15)
COUNTRY VARCHAR2(15)
PROMO CHAR(1)
Yes I've tried changing state to CHAR and I get the same message.
You must fully specify the VARIABLE types and add the maximum varchar2 sizes.
If you use the following block, it works as expected:
VARIABLE g_fname VARCHAR2(60)
VARIABLE g_city VARCHAR2(60)
VARIABLE g_state VARCHAR2(60)
VARIABLE g_phone VARCHAR2(60)
VARIABLE g_email VARCHAR2(60)
EXECUTE shop_query_pkg.shop_info_pp(23, :g_fname, :g_city, :g_state, :g_phone, :g_email);
PRINT :g_fname
PRINT :g_city
PRINT :g_state
PRINT :g_phone
PRINT :g_email
CREATE or REPLACE PROCEDURE SP_INSERT_OVERSEAS_COMPANY
(
COMPANY_CODE IN NUMBER,
COMPANY_NAME IN VARCHAR2,
STREET_ADDR IN VARCHAR2,
COMPANY_STATE IN VARCHAR2,
ZIP_CODE IN VARCHAR2,
COUNTRY IN VARCHAR2,
CONTACT_PERSON IN VARCHAR2,
CONTACT_NUMBER IN VARCHAR2
)
AS
BEGIN
IF sysdate between trunc(sysdate,'DD')+interval '9' hour and trunc(sysdate,'DD')+interval '17' hour
THEN
INSERT INTO Overseas_Company
VALUES
(COMPANY_NAME,COMPANY_NAME,STREET_ADDR,COMPANY_STATE,ZIP_CODE,COUNTRY,CONTACT_PERSON,CONTACT_NUMBER);
ELSE
dbms_output.put_line ('Process is outside of normally working hours');
END IF;
END SP_INSERT_OVERSEAS_COMPANY;
/
Should COMPANY_NAME,COMPANY_NAME,... be COMPANY_CODE,COMPANY_NAME,...? The parameter COMPANY_CODE is not used in the procedure. Are you getting numeric conversion errors?