I'm trying to create a procedure that inserts a new row in a table deposit/uttag, throws an exception if you are not authorized to do this transaction. I'm supposed to create a function that checks if someone is authorized or not, and then use that function in this procedure.
I keep getting this error which I don't get:
Errors: PROCEDURE DO_UTTAG
Line/Col: 18/22 PLS-00049: bad bind variable 'NEW.PNR'
Line/Col: 18/31 PLS-00049: bad bind variable 'NEW.KNR'
Quick translations:
Saldo=balance
konto= account
pnr= personal number
knr= customer number
belopp= amount
These are the main tables:
CREATE TABLE bankkund(
PNR VARCHAR2(11) PRIMARY KEY,
FNAMN VARCHAR2(25) NOT NULL,
ENAMN VARCHAR2(25) NOT NULL ,
PASSWD VARCHAR2(16) NOT NULL,
UNIQUE(PASSWD));
CREATE TABLE kontotyp(
KTNR NUMBER(6)PRIMARY KEY,
KTNAMN VARCHAR2(20)NOT NULL,
RÄNTA NUMBER(5,2) NOT NULL);
CREATE TABLE konto(
KNR NUMBER(8)PRIMARY KEY,
KTNR NUMBER(6)NOT NULL,
REGDATUM DATE NOT NULL,
SALDO NUMBER(10,2),
FOREIGN KEY(ktnr) REFERENCES kontotyp(ktnr));
CREATE TABLE uttag(
RADNR NUMBER(9) PRIMARY KEY,
PNR VARCHAR2(11)NOT NULL,
KNR NUMBER(8)NOT NULL,
BELOPP NUMBER(10,2),
DATUM DATE NOT NULL,
FOREIGN KEY(pnr) REFERENCES bankkund(pnr),
FOREIGN KEY(knr) REFERENCES konto(knr));
This is the procedure:
create or replace procedure do_uttag (
p_radnr kontoägare.radnr%TYPE,
p_pnr bankkund.pnr%TYPE,
p_knr konto.knr%TYPE,
p_belopp uttag.belopp%TYPE)
as
v_saldo konto.saldo%type;
begin
select saldo
into v_saldo
from konto;
insert into uttag(
radnr, pnr, knr, belopp, datum
) values (
p_radnr, p_pnr, p_knr, p_belopp, SYSDATE
);
if get_behörighet(:NEW.PNR,:NEW.KNR) = 0
then
raise_application_error(-20101, 'Du har inte behörigheten!');
else
update konto
set saldo = v_saldo - p_belopp;
dbms_output.put_line('Saldot är nu = ' ||(v_saldo - p_belopp));
end if;
end;
/
This is the function that I created for authorization:
create or replace function get_behörighet (
p_pnr in bankkund.pnr%type,
p_knr in konto.knr%type)
return number
is
v_pnr bankkund.pnr%type;
v_knr konto.knr%type;
begin
select bankkund.pnr, konto.knr
into v_pnr, v_knr
from bankkund, konto
where bankkund.pnr = p_pnr
and konto.knr = p_knr;
return 1;
exception
when others then
return 0;
end;
/
Would really appreciate the help!!
get_behörighet(:NEW.PNR,:NEW.KNR)
this is a form of addressing fields allowed in triggers
Related
I am using Oracle database 19c for a project. I have created the alumni table as shown below:
CREATE TABLE Alumni (
ID NUMBER GENERATED ALWAYS AS IDENTITY ,
First_Name varchar2(20) NOT NULL,
Last_Name varchar2(20) NOT NULL,
Gender char(1) NOT NULL,
CHECK (Gender IN('M','F')),
Graduation_Year number NOT NULL,
check (Graduation_Year>=1980 AND Graduation_Year<=2020),
Degree_Course varchar2(255) not null,
Award_Nominated CHAR(1),
CHECK (Award_Nominated IN('Y','N')),
Award_Won CHAR(1),
CHECK (Award_Won IN('Y','N')),
Phone_Number VARCHAR2(15) not null,
Email_Address VARCHAR2(255) not null,
CONSTRAINT ALUM_PK PRIMARY KEY(ID)
);
Then I tried to define a function that will allow me to search by First or last name in a section of the table, shown below:
CREATE OR REPLACE TYPE alum_row_type is object(ID number,First_name varchar2(20),Last_Name
varchar2(20),Phone_number varchar2(15),Email_Address varchar2(255));
CREATE OR REPLACE TYPE t_alum_row_type as table of alum_row_type;
CREATE OR REPLACE FUNCTION Name_Search RETURN t_alum_row_type
IS
L_alum_row t_alum_row_type := t_alum_row_type();
X integer :=0;
BEGIN
FOR R IN (SELECT ID,First_Name, Last_Name,Phone_Number,Email_Address FROM alumni)
LOOP
L_alum_row.extend;
X:=X+1;
L_alum_row(X):= alum_row_type(X.ID,X.First_Name, X.Last_Name, X.Phone_Number, X.Email_Address);
END LOOP;
RETURN L_alum_row;
END;
After running this, I get this error:
LINE/COL ERROR
--------- -------------------------------------------------------------
10/9 PL/SQL: Statement ignored
10/41 PLS-00487: Invalid reference to variable 'X'
Errors: check compiler log
How can I resolve this issue. I am relatively new to PL\SQL, so please explain it simply.
This is not possible
L_alum_row(X):= alum_row_type(X.ID,X.First_Name, X.Last_Name, X.Phone_Number, X.Email_Address);
You are referencing X.ID, X.Phone_Number etc. . . but declared X as an integer. If you are trying to access the current loop record, try with
L_alum_row(X):= alum_row_type(R.ID,R.First_Name, R.Last_Name, R.Phone_Number, R.Email_Address);
As you declared the loop iterator as R for your cursor
FOR R IN (SELECT ID,First_Name, Last_Name,Phone_Number,Email_Address FROM alumni)
You can eliminate the loop altogether by using BULK COLLECT. Thereby reducing the function to basically a single select statement.
function name_search
return t_alum_row_type
is
l_alum_row t_alum_row_type := t_alum_row_type();
begin
select alum_row_type(id,first_name, last_name,phone_number,email_address)
bulk collect
into l_alum_row
from alumni;
return l_alum_row;
end;
I'm trying to write a procedure. When we query this procedure with id no,
the tables will be joined and the results will be as follows;
(PROCEDURE_NAME: "student_information")
id_no, name, surname, school_number, department_information, city, lesson
Here are my tables and procedure code;
CREATE TABLE student_info (
school_number NUMBER,
id_no NUMBER NOT NULL UNIQUE,
name VARCHAR2(50) NOT NULL,
surname VARCHAR2(50) NOT NULL,
city VARCHAR2(50) NOT NULL,
birth_date DATE NOT NULL,
CONSTRAINT student_info_pk PRIMARY KEY (okul_numarasi)
);
CREATE TABLE school_info (
school_number NUMBER,
entry_date DATE NOT NULL,
faculty_info VARCHAR2(50) NOT NULL,
department_information VARCHAR2(50) NOT NULL,
CONSTRAINT school_info_pk PRIMARY KEY (school_number),
CONSTRAINT student_school_fk FOREIGN KEY (school_number)
REFERENCES student_info(school_number)
);
CREATE TABLE lessons(
school_number NUMBER,
lesson_name VARCHAR2(100) NOT NULL,
lesson_number NUMBER NOT NULL,
midterm_1 NUMBER,
midterm_2 NUMBER,
final_note NUMBER,
integration_note NUMBER,
CONSTRAINT lessons_pk PRIMARY KEY (school_number),
CONSTRAINT lessons_student_fk FOREIGN KEY (school_number)
REFERENCES ogrenci_bilgileri (okul_numarasi)
);
CREATE OR REPLACE PROCEDURE
student_information(
p_no IN student_info.id_no%type,
p_name OUT student_info.name%type,
p_surname OUT student_info.surname%type,
p_school_number OUT student_info.school_number%type,
p_department_information OUT school_info.department_information%type,
p_city OUT student_info.city%type,
p_lesson OUT lessons.lesson_name%type
) AS
BEGIN
SELECT o.name,
o.surname,
o.school_number,
ok.department_information,
o.city,
d.lesson_name
INTO p_name,
p_surname,
p_school_number,
p_city,
p_department_information,
p_lesson
FROM student_info o
JOIN school_info ok
ON o.school_info = ok.school_number
JOIN lessons d
ON d.school_number = ok.school_number;
WHERE o.id_no = p_no;
END student_information;
And here is my declare to run the procedure.
DECLARE
v_id student_info.id_no%type:= 12345;
v_name student_info.name%type;
v_surname student_info.surname%type;
v_school_num student_info.school_number%type;
v_department school_info.department_information%type;
v_city student_info.city%type;
v_lesson lessons.lesson_name%type;
BEGIN
student_information(v_id,v_name,v_surname,v_school_num,v_department,v_city, v_lesson );
DBMS_OUTPUT.put_line ('Student Information');
DBMS_OUTPUT.put_line ('ID: ' || v_id);
DBMS_OUTPUT.put_line ('Name: ' || v_name || ' ' || v_surname);
DBMS_OUTPUT.put_line ('School Number: ' || v_school_num);
DBMS_OUTPUT.put_line ('Department Information: ' || v_department);
DBMS_OUTPUT.put_line ('City: ' || v_city);
DBMS_OUTPUT.put_line ('Lesson Name:' || v_lesson);
END;
The error is:
ORA-06502: PL / SQL: numerical or value error: character-to-number error
ORA-06512: location "SYSTEM.student_information", line 12
ORA-06512: location line 10
06502. 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.
Simple mismatch on your columns
SELECT o.name,
o.surname,
o.school_number,
ok.department_information, <===
o.city, <===
d.lesson_name
INTO p_name,
p_surname,
p_school_number,
p_city, <===
p_department_information, <===
p_lesson
but before you slap your head and think you've wasted your time, the changes you have made (to using %TYPE etc) have made your code so much more robust and maintainable.
I am a first timer in Oracle and using Netbean IDE 8 and I am trying to prevent deletion of a Hotel from Hotel Table if Room Table has Room details for the Hotel. These 2 tables are on 2 different sites so have to use trigger. I tried the following code but it throws error like following with sql error on line 6, 10, 13, 14,
[Exception, Error code 6,550, SQLState 65000] ORA-06550: line 4,
column 19: PLS-00049: bad bind variable '' ORA-06550: line 4, column
30: PLS-00103: Encountered the symbol "end-of-file" when expecting one
of the following:
the table structure is
CREATE TABLE Hotel
(
HotelID number not null,
HotelName varchar2(100) not null,
HotelType varchar2(10) not null,
ConstrYear varchar2(10) null,
Country varchar2 (100) not null,
City varchar2 (50) not null,
Address varchar2 (100) not null,
ContactNo varchar2(50) not null,
Email varchar2(100) null,
CONSTRAINT Hotel_pk PRIMARY KEY (HotelID)
);
and for Room
CREATE TABLE Room
(
RoomID number not null,
HotelID raw(16) not null,
RoomNo number not null,
RoomType varchar2(20) not null,
Price numeric(10,2) not null,
RoomDesc varchar2(255) not null,
CONSTRAINT Room_pk PRIMARY KEY (RoomID),
);
What am I doing wrong? Please help.
CREATE OR REPLACE TRIGGER CHECK_Room
BEFORE DELETE on Hotel
FOR each ROW
declare
rowcount number;
begin
SELECT COUNT(HotelID) INTO rowcount
from ROOM#site1
where HotelID = :OLD.HotelID;
if rowcount>0
THEN
Raise_Application_Error (-20100, 'This Hotel has room details in Room table.');
end if;
end;
The below should work for you, provided your database link is in good shape.
I'd recommend staying away from using a reserved word as a variable name. One common convention is to prefix variable names with "v" as in this example.
I'd also recommend qualifying schema names over the database link. THE_USER is a placeholder here as is THE_OTHER_DATABASE. Please replace with site1, etc. as needed.
First create the tables, in your case in two databases:
--This database
CREATE TABLE HOTEL(HOTELID NUMBER);
--(On the other database)
CREATE TABLE ROOM(HOTELID NUMBER);
-- ... Set up database link
CREATE OR REPLACE TRIGGER CHECK_ROOM
BEFORE DELETE ON HOTEL
FOR EACH ROW
DECLARE
V_ROWCOUNT NUMBER;
BEGIN
SELECT COUNT(HOTELID)
INTO V_ROWCOUNT
FROM THE_USER.ROOM#THE_OTHER_DATABASE
WHERE ROOM.HOTELID = :OLD.HOTELID;
IF V_ROWCOUNT > 0
THEN
Raise_Application_Error(-20100, 'This Hotel has room details in Room table.');
END IF;
END;
/
Then test it:
--Here
INSERT INTO HOTEL VALUES(19);
COMMIT;
--There
INSERT INTO ROOM VALUES(19);
COMMIT;
Then:
DELETE FROM HOTEL;
DELETE FROM HOTEL
*
ERROR at line 1:
ORA-20100: This Hotel has room details in Room table.
i don't know how to start !!
i have a work in oracle database,and it is all about triggers and constraints ...
the work is to create triggers and constraints on some tables of database of league of hokey ...
and since i'm new , and not familiar with triggers i have a lot of errs!!!
let's take these two tables as exemple :
1/ "equipe" (means team) table :
Name Null? Type
----------------------------------------- -------- ----------------------------
ID_EQ NOT NULL NUMBER(6)
NOM VARCHAR2(50)
ENREGISTRMENT VARCHAR2(50)
ID_LIG NUMBER(6)
ID_CAPITAINE NUMBER(6)
ID_ENT NUMBER(6)
2/ "joueur" (means player) :
Name Null? Type
----------------------------------------- -------- ----------------------------
ID_JOU NOT NULL NUMBER(6)
NUMERO NUMBER(4)
POSITION VARCHAR2(50)
ID_EQ NUMBER(6)
where :
"id_eq" and "id_jou" are primary keys.
"joueur.id_eq" is referenced to "equipe.id_eq".
"equipe.id_capitaine" is referenced to "joueur.id_jou".
i want to create a trigger that write a msg of err if the user insert in or update the table "equipe" where the "capitaine" is not a player in the team ("equipe") , i try a lot , buttt ... always the msg:
Warning: Trigger created with compilation errors.
This is one of the triggers , if someone can find the err and fix it , or suggest a better one :
CREATE OR REPLACE TRIGGER capitaine_in_equipe
before UPDATE OR INSERT ON equipe
FOR EACH ROW
DECLARE
id_p joueur.id_eq%TYPE;
BEGIN
if (:new.iq_capitaine is not null ) then
SELECT id_eq INTO id_p
FROM joueur
WHERE id_jou = :new.iq_capitaine;
IF ( id_p != :new.id_eq ) THEN
raise_application_error(-20100,' the captain is not a player of the team');
END IF;
END IF;
END;
and if you know some good references of triggers, pl/sql Oracle for biggeners put it, please!
thank you ;)
Surely, there are other way to implement your logic, but if you want to use your trigger, the following works for me
Create equipe:
CREATE TABLE equipe
( ID_EQ number(6) not null,
NOM varchar2(50),
ENREGIS number(6),
ID_CAPITAINE number(6),
ID_ENT number(6),
CONSTRAINT equipe_pk PRIMARY KEY (ID_EQ)
);
Create joueur:
create table joueur
(ID_JOU number(6) not null,
NUMERO number(4),
POSITION varchar2(50),
ID_EQ number(6),
CONSTRAINT joueur_pk PRIMARY KEY (id_jou)
);
Alter both with the foreign key:
alter table equipe add(CONSTRAINT fk_equipe
FOREIGN KEY (ID_CAPITAINE)
REFERENCES joueur(ID_JOU));
alter table joueur add(CONSTRAINT fk_joueur
FOREIGN KEY (id_eq)
REFERENCES equipe(ID_EQ));
Create your trigger:
CREATE OR REPLACE TRIGGER capitaine_in_equipe
before UPDATE OR INSERT ON equipe
FOR EACH ROW
DECLARE
id_p joueur.id_eq%TYPE;
BEGIN
if (:new.id_capitaine is not null ) then
SELECT id_eq INTO id_p
FROM joueur
WHERE id_jou = :new.id_capitaine;
IF ( id_p != :new.id_eq ) THEN
raise_application_error(-20100,' the captain is not a player of the team');
END IF;
END IF;
END;
Notice in your tables definition, you mentioned a column id_capitaine. In your trigger you used the name iq_capitaine. I'm not sure if that reflects your real code or just a typo here.
I have a stored procedure in Oracle 9i which inserts records in a table. The table has a primary key built to ensure duplicte rows doesnot exists.
I am trying to insert a record by calling this stored procedure and it works first time properly. I am again trying to insert a duplicate record and expecting unique constraint violation error. But I am getting
ORA-01401 inserted value too large for column
I knew its meaning but my query is , if the value inserted is really large then how it got successful in the first attempt.
Table is
CREATE TABLE KEY
(
ID VARCHAR2(25 BYTE),
KEY NUMBER(4) NOT NULL,
INSERT_DATE DATE,
WORK_KEY VARCHAR2(128 BYTE)
)
CREATE UNIQUE INDEX SACHINIDX ON KEY
(ID, KEY)
Call is
EXEC SQL EXECUTE
BEGIN
keyadd(:id, :key, :wkey);
END;
END-EXEC;
Stored Procedure is
PROCEDURE keyadd(id IN VARCHAR2, key IN NUMBER, wkey IN VARCHAR2)
{
BEGIN
INSERT INTO KEY
( ID,
KEY,
INSERT_DATE,
WORK_KEY)
VALUES
(
id,
key,
SYSDATE,
wkey
);
EXCEPTION
ROLLBACK;
COMMIT;
RETURN;
END;
}
First insert sqlca.sqlcode is [0]
Second insert sqlca.sqlcode is [-1401]
CREATE TABLE KEY
(
ID VARCHAR2(25 BYTE),
KEY NUMBER(4) NOT NULL,
INSERT_DATE DATE,
WORK_KEY VARCHAR2(128 BYTE)
);
CREATE UNIQUE INDEX SACHINIDX ON KEY
(ID, KEY);
create or replace PROCEDURE keyadd(id IN VARCHAR2, key IN NUMBER, wkey IN VARCHAR2)
is
BEGIN
INSERT INTO KEY
( ID,
KEY,
INSERT_DATE,
WORK_KEY)
VALUES
(
id,
key,
SYSDATE,
wkey
);
COMMIT;
-- EXCEPTION when others then
-- ROLLBACK;
end keyadd;
/
begin
keyadd('one', 1, '59FC9AD0FA5A8932836824B0489B73252C120301A2205154C096B4EB213FA983D5E500B62A469439');
keyadd('one', 1, '905BD61AAEC986ACF887DBA7C04D650B61A8818ABEBE1720D810B4A426EB9220558B530D5119315F');
end;
/
gives me the expected ORA-00001: Unique Constraint... error, not an ORA-01401. So, without further information its impossible to help.
I don't know the language the procedure was written in, but this part:
EXCEPTION
ROLLBACK;
COMMIT;
RETURN;
raises my eyebrows. Two questions:
What is this supposed to do?
Is your issue solved when you remove those lines?
My best guess is on your second try, you are providing a value for one of the other columns that is too large. Looks like this error will supersede the primary key violation.