How to insert foreign key from pre-generated table? - sql

I have 3 tables:
create table customer
(
customer_id integer primary key,
customer_first_name varchar2(50) not null,
customer_surrname varchar2(50) not null,
phone_number varchar2(15) not null,
customer_details varchar2(200) default 'There is no special notes'
);
create table place
(
table_number integer primary key,
table_details varchar2(200) default 'There is no details'
);
create table booking
(
booking_id integer primary key,
date_of_booking date,
number_of_persons number(2) not null,
customer_id integer not null,
foreign key(customer_id) references customer(customer_id),
table_number integer not null,
foreign key(table_number) references place(table_number)
);
I have to generate customer table using this kind of generator:
set SERVEROUTPUT on format wrapped;
set define off;
drop sequence customer_seq;
drop sequence place_seq;
--CUSTOMER TABLE INSERT ROW GENERATOR
create sequence customer_seq START WITH 1 INCREMENT BY 1 NOMAXVALUE;
CREATE OR REPLACE TRIGGER customer_id_trigger
BEFORE INSERT ON customer
FOR EACH ROW
BEGIN
SELECT customer_seq.nextval INTO :new.customer_id FROM dual;
END;
/
DELETE FROM customer;
DECLARE
TYPE TABSTR IS TABLE OF VARCHAR2(250);
first_name TABSTR;
surrname TABSTR;
qname number(5);
phonenum number(15);
details TABSTR;
BEGIN
first_name := TABSTR ('Jhon','Poul','Jesica','Arnold','Max','Teemo','Tim','Mikel','Michael',
'Kristian','Adela','Mari','Anastasia','Robert','Jim','Juana','Adward',
'Jana','Ola','Kristine','Natali','Corey','Chester','Naomi','Chin-Chou');
surrname := TABSTR ('Grey','Brown','Robins','Chiho','Lee','Das','Edwins','Porter','Potter',
'Dali','Jordan','Jordison','Fox','Washington','Bal','Pitney','Komarowski',
'Banks','Albra','Shwiger');
details := TABSTR ('Exellent Customer','Good Customer','Always drunked','Left big tips',
'Bad Customer','Did not pay last bill','New Customer','VIP client');
qname := 100; — CHANGE THIS TO MANAGE HOW MANY ROWS YOU WANT TO BE ADDED
FOR i IN 1..qname LOOP
phonenum := dbms_random.value(111111111,999999999);
INSERT INTO customer VALUES (NULL, first_name(dbms_random.value(1,25)),
surrname(dbms_random.value(1,20)), phonenum, details(dbms_random.value(1,8)));
END LOOP;
DBMS_OUTPUT.put_line('Customers done!');
END;
/
--TABLE INSERT
DELETE FROM place;
create sequence place_seq start with 1 increment by 1;
insert into place values (place_seq.nextval, 'Near the window');
insert into place values (place_seq.nextval, default);
insert into place values (place_seq.nextval, 'Near the door');
insert into place values (place_seq.nextval, 'Near the window');
insert into place values (place_seq.nextval, 'Near the window');
insert into place values (place_seq.nextval, default);
insert into place values (place_seq.nextval, 'Near the door');
insert into place values (place_seq.nextval, 'Big table');
insert into place values (place_seq.nextval, default);
insert into place values (place_seq.nextval, 'Big table');
So the question is how can I insert client_id in "booking" table which have one of the numbers in "customers" table? Because every time I regenerate data in "Customers" table numbers are changing so I should somehow select numbers in an array and then randomly choose one of them from this array. The thing is I don't really know how to select from table to array. Can anybody help?

For PL/SQL version you can use BULK COLLECT and standard sys.odcinumberlist array.
create sequence booking_seq start with 1 increment by 1;
declare
customerIds sys.odcinumberlist;
placeIds sys.odcinumberlist;
number_of_generated_records number := 150; -- number of records to be generated
begin
-- fill the array of customer_id values
select customer_id
bulk collect into customerIds
from customer;
-- fill the array of place numbers
select table_number
bulk collect into placeIds
from place;
for i in 1..number_of_generated_records loop
insert into booking(booking_id,date_of_booking,number_of_persons,customer_id,table_number)
values(
booking_seq.nextval, -- booking_id
trunc(sysdate) + round(dbms_random.value(1,365)), -- date_of_booking
round(dbms_random.value(1,99)), -- number_of_persons
customerIds(round(dbms_random.value(1,customerIds.count))), -- customer_id
placeIds(round(dbms_random.value(1,placeIds.count))) -- table_number
);
end loop;
end;
But, for your case I would prefer pure sql:
insert into booking(booking_id,date_of_booking,number_of_persons,customer_id,table_number)
with
customer_subq as (
select customer_id, row_number() over (order by customer_id) rn from customer
),
place_subq as (
select table_number, row_number() over (order by table_number) rn from place
),
params as (
select 1500 number_of_generated_records,
(select count(1) from customer) customer_count,
(select count(1) from place) place_count
from dual
),
random_numbers as (
select round(dbms_random.value(1,1000)) random_number1,
round(dbms_random.value(1,1000)) random_number2,
round(dbms_random.value(1,1000)) random_number3,
round(dbms_random.value(1,1000)) random_number4
from dual,params
connect by level <= number_of_generated_records
)
select booking_seq.nextval booking_id,
trunc(sysdate) + mod(random_number1,365) date_of_booking,
mod(random_number1,100) number_of_persons,
customer_id,
table_number
from random_numbers,
params,
customer_subq,
place_subq
where mod(random_number1,customer_count) + 1 = customer_subq.rn
and mod(random_number2,place_count) + 1 = place_subq.rn

Related

Update multiple tables in trigger where one of the tables is used for trigger activation

Let's say I have two tables called widgetCustomer and widgetSale. On an insert in widgetSale I want to add a timestamp to the widgetSale row and add the sale id as last_order_id to the widgetCustomer table.
I understand using AFTER INSERT ON will result in an error on trying to update the NEW row, hence we need to use BEFORE INSERT ON clause. Which brings forward a new issue that AUTO_INCREMENT has not yet generated a id for sale hence last_order_id would all be zero. There is a method to do this at MySQL/MariaDB TRIGGER but it seems to fail on my system (i.e., the last order ids are still zero).
As a work around I'm using two different triggers one before insert and one after insert. Although it does work I'm keen to learn if there is a possible flaws with the method above and is there a better way of doing this (both in terms of performance and data integrity).
My code is given below:
DROP TABLE IF EXISTS widgetSale;
DROP TABLE IF EXISTS widgetCustomer;
DROP TABLE IF EXISTS widgetLog;
CREATE TABLE widgetCustomer ( id integer primary key AUTO_INCREMENT, name TEXT, last_order_id INT, stamp TEXT );
CREATE TABLE widgetSale ( id integer primary key AUTO_INCREMENT, item_id INT, customer_id INTEGER, quan INT, price INT, stamp TEXT );
CREATE TABLE widgetLog ( id integer primary key AUTO_INCREMENT, stamp TEXT, event TEXT, username TEXT, tablename TEXT, table_id INT);
INSERT INTO widgetCustomer (name) VALUES ('Bob');
INSERT INTO widgetCustomer (name) VALUES ('Sally');
INSERT INTO widgetCustomer (name) VALUES ('Fred');
SELECT * FROM widgetCustomer;
CREATE TRIGGER stampSale BEFORE INSERT ON widgetSale
FOR EACH ROW BEGIN
SET NEW.stamp = CURRENT_TIMESTAMP();
END
CREATE TRIGGER stampOnRest AFTER INSERT ON widgetSale
FOR EACH ROW BEGIN
UPDATE widgetCustomer SET last_order_id = NEW.id, stamp = CURRENT_TIMESTAMP()
WHERE widgetCustomer.id = NEW.customer_id;
INSERT INTO widgetLog (stamp, event, username, tablename, table_id)
VALUES (CURRENT_TIMESTAMP(), 'INSERT', 'TRIGGER', 'widgetSale', NEW.id);
END
INSERT INTO widgetSale (item_id, customer_id, quan, price) VALUES (1, 3, 5, 1995);
INSERT INTO widgetSale (item_id, customer_id, quan, price) VALUES (2, 2, 3, 1495);
INSERT INTO widgetSale (item_id, customer_id, quan, price) VALUES (3, 1, 1, 2995);
SELECT * FROM widgetSale;
SELECT * FROM widgetCustomer;
SELECT * FROM widgetLog;
I'm using mariadb 10.6.* on Archlinux.

How to create an Oracle audit trigger?

CREATE OR REPLACE TRIGGER EVALUATION
BEFORE INSERT OR UPDATE OR DELETE ON BOOKING
FOR EACH ROW
DECLARE
BEGIN
SELECT BOOKING_EVALUATION FROM BOOKING WHERE BOOKING_EVALUATION > 2;
SELECT BOOKING_EVALUATION INTO EVALUATIONAUDIT FROM BOOKING;
IF INSERTING THEN
INSERT INTO EVALUATIONAUDIT (VOYAGES_ID,CUSTOMER_NAME,START_DATE,SHIP_NAME,BOOKING_EVALUATION)
VALUES(:NEW.VOYAGES_ID,:NEW.CUSTOMER_NAME,:NEW.START_DATE,:NEW.SHIP_NAME,:NEW.BOOKING_EVALUATION);
END IF;
IF UPDATING THEN
INSERT INTO EVALUATIONAUDIT (VOYAGES_ID,CUSTOMER_NAME,START_DATE,SHIP_NAME,BOOKING_EVALUATION)
VALUES(:OLD.VOYAGES_ID,:OLD.CUSTOMER_NAME,:OLD.START_DATE,:OLD.SHIP_NAME,:OLD.BOOKING_EVALUATION);
END IF;
IF DELETING THEN
INSERT INTO EVALUATIONAUDIT (VOYAGES_ID,CUSTOMER_NAME,START_DATE,SHIP_NAME,BOOKING_EVALUATION)
VALUES(:OLD.VOYAGES_ID,:OLD.CUSTOMER_NAME,:OLD.START_DATE,:OLD.SHIP_NAME,:OLD.BOOKING_EVALUATION);
END IF;
END;
This is my audit table:
desc evaluationaudit;
Name Null? Type
----------------------------------------- -------- -----------------------
AUDITT_ID NOT NULL NUMBER(10)
VOYAGES_ID NOT NULL NUMBER(10)
CUSTOMER_NAME NOT NULL VARCHAR2(20)
START_DATE NOT NULL DATE
SHIP_NAME NOT NULL VARCHAR2(20)
BOOKING_EVALUATION NOT NULL NUMBER(20)
and this is my show error output:
SQL> SHOW ERRORS;
Errors for TRIGGER EVALUATION:
LINE/COL ERROR
-------- -------------------------------------------------------------
12/24 PLS-00049: bad bind variable 'NEW.CUSTOMER_NAME'
12/43 PLS-00049: bad bind variable 'NEW.START_DATE'
12/59 PLS-00049: bad bind variable 'NEW.SHIP_NAME'
18/24 PLS-00049: bad bind variable 'OLD.CUSTOMER_NAME'
18/43 PLS-00049: bad bind variable 'OLD.START_DATE'
18/59 PLS-00049: bad bind variable 'OLD.SHIP_NAME'
24/24 PLS-00049: bad bind variable 'OLD.CUSTOMER_NAME'
24/43 PLS-00049: bad bind variable 'OLD.START_DATE'
24/59 PLS-00049: bad bind variable 'OLD.SHIP_NAME'
I wanted to add to the audit table. If a customer gives a poor evaluation of 2 or less, the details of their voyage (customer_name, name and date of the cruise, ship name and evaluation) but I'm getting error
Warning: Trigger created with compilation errors.
And the audit table is empty, showing no rows selected. I can't seem to find the problem where I am going wrong.
Maybe the following code snippets will help you. Suppose we have 2 tables: BOOKING, and EVALUATION_AUDIT (everything written in uppercase letters is taken from the code in your question).
Tables
create table booking (
VOYAGES_ID number primary key
, CUSTOMER_NAME VARCHAR2(20) NOT NULL
, START_DATE DATE NOT NULL
, SHIP_NAME VARCHAR2(20) NOT NULL
, BOOKING_EVALUATION NUMBER(20) NOT NULL
) ;
create table evaluationaudit (
AUDITT_ID number generated always as identity start with 5000 primary key
, trg_cond_pred varchar2( 64 ) default 'Row not added by evaluation trigger!'
, VOYAGES_ID NUMBER(10) NOT NULL
, CUSTOMER_NAME VARCHAR2(20) NOT NULL
, START_DATE DATE NOT NULL
, SHIP_NAME VARCHAR2(20) NOT NULL
, BOOKING_EVALUATION NUMBER(20) NOT NULL
) ;
Trigger
-- "updating" and "deleting" code omitted for clarity
CREATE OR REPLACE TRIGGER EVALUATION_trigger
BEFORE INSERT OR UPDATE OR DELETE ON BOOKING
FOR EACH ROW
BEGIN
case
when INSERTING then
if :new.booking_evaluation <= 2 then
INSERT INTO EVALUATIONAUDIT
( trg_cond_pred,
VOYAGES_ID, CUSTOMER_NAME, START_DATE, SHIP_NAME, BOOKING_EVALUATION )
VALUES (
'INSERTING'
, :NEW.VOYAGES_ID
, :NEW.CUSTOMER_NAME
, :NEW.START_DATE
, :NEW.SHIP_NAME
, :NEW.BOOKING_EVALUATION
);
end if ;
end case ;
END ;
/
Testing
One of your requirements (in your question) is:
I wanted to add to the audit table. If a customer gives a poor
evaluation of 2 or less, the details of their voyage (customer_name,
name and date of the cruise, ship name and evaluation)
delete from evaluationaudit ;
delete from booking ;
-- booking_evaluation greater than 2 -> no entry in audit table
insert into booking
( VOYAGES_ID, CUSTOMER_NAME, START_DATE, SHIP_NAME, BOOKING_EVALUATION )
values ( 1111, 'customer1', date '2018-05-24', 'ship1', 9999 ) ;
select * from evaluationaudit ;
-- no rows selected
-- booking_evalution = 2 -> insert a row into the audit table
insert into booking
( VOYAGES_ID, CUSTOMER_NAME, START_DATE, SHIP_NAME, BOOKING_EVALUATION )
values ( 1112, 'customer1', date '2018-05-24', 'ship1', 2 ) ;
select * from evaluationaudit ;
AUDITT_ID TRG_COND_PRED VOYAGES_ID CUSTOMER_NAME START_DATE SHIP_NAME BOOKING_EVALUATION
5000 INSERTING 1112 customer1 24-MAY-18 ship1 2
__Update__
If - as you wrote in your comment - you need to pull in some more data from other tables, maybe you want to try the following approach: keep the trigger code rather brief, and use it to call a procedure for the more complicated stuff eg
Tables
create table evaluationaudit (
AUDITT_ID number generated always as identity start with 7000 primary key
, trg_cond_pred varchar2( 64 ) default 'Row not added by evaluation trigger!'
, VOYAGES_ID NUMBER NOT NULL
, CUSTOMER_NAME VARCHAR2(20) NOT NULL
, SHIP_NAME VARCHAR2(20) NOT NULL
, BOOKING_EVALUATION NUMBER(20) NOT NULL
) ;
create table ships ( name varchar2( 64 ), id number unique ) ;
create table customers ( name varchar2( 64 ), id number unique ) ;
insert into ships ( name, id ) values ( 'ship1', 501 );
insert into ships ( name, id ) values ( 'ship2', 502 );
insert into ships ( name, id ) values ( 'ship3', 503 );
insert into customers ( name, id ) values ( 'customer1', 771 ) ;
insert into customers ( name, id ) values ( 'customer2', 772 ) ;
insert into customers ( name, id ) values ( 'customer3', 773 ) ;
create table bookings (
id number generated always as identity start with 5000 primary key
, voyagesid number
, shipid number
, customerid number
, evaluation number
, bookingdate date
);
Trigger
create or replace trigger bookingeval
before insert on bookings
for each row
when ( new.evaluation <= 2 ) -- Use NEW without colon here! ( see documentation )
begin
auditproc( :new.voyagesid, :new.customerid, :new.shipid, :new.evaluation ) ;
end ;
/
Procedure
create or replace procedure auditproc (
voyagesid_ number
, customerid_ number
, shipid_ number
, evaluation_ number
)
as
customername varchar2( 64 ) := '' ;
shipname varchar2( 64 ) := '' ;
begin
-- need to find the customername and shipname before INSERT
select name into customername from customers where id = customerid_ ;
select name into shipname from ships where id = shipid_ ;
insert into evaluationaudit
( trg_cond_pred,
voyages_id, customer_name, ship_name, booking_evaluation )
values (
'INSERTING'
, voyagesid_
, customername
, shipname
, evaluation_
);
end ;
/
Testing
-- evaluation > 2 -> no INSERT into evaluationaudit
insert into bookings
( voyagesid, customerid, shipid, evaluation, bookingdate )
values ( 1111, 771, 501, 9999, sysdate ) ;
select * from evaluationaudit ;
-- no rows selected
-- evaluation = 2
-- -> trigger calling audit procedure -> inserts into evaluationaudit
insert into bookings
( voyagesid, customerid, shipid, evaluation, bookingdate )
values ( 1112, 772, 502, 2, sysdate ) ;
select * from evaluationaudit ;
AUDITT_ID TRG_COND_PRED VOYAGES_ID CUSTOMER_NAME SHIP_NAME BOOKING_EVALUATION
7000 INSERTING 1112 customer2 ship2 2

how can i access a value that's being updated by a trigger?

here's the value of ACCOUNT_NUMBER that has been generated by a sequence and inserted in ACCOUNTS table by ACCOUNT_NUMBER_TRIG trigger that i need to insert it into the TRANSACTION TABLE by the trigger ACCOUNTS_TRANSCATION_TRIG_1
CREATE OR REPLACE TRIGGER ACCOUNT_NUMBER_TRIG
BEFORE INSERT
ON ACCOUNTS
FOR EACH ROW
WHEN (NEW.ACCOUNT_NUMBER is not null)
DECLARE
V_ACC_NO ACCOUNTS.ACCOUNT_NUMBER%TYPE;
BEGIN
SELECT ACCOUNT_NO_SEQ.nextvaL INTO V_ACC_NO FROM DUAL;
:NEW.ACCOUNT_NUMBER := V_ACC_NO;
END ACCOUNT_NUMBER_TRIG;
------------------------------------------------------------------------------
CREATE OR REPLACE TRIGGER ACCOUNTS_TRANSCATION_TRIG_1 AFTER
INSERT ON ACCOUNTS FOR EACH ROW DECLARE CURSOR ACCOUNTS_CUR IS
SELECT ACCOUNT_NUMBER FROM ACCOUNTS;
DECLARE
TEMP_1 NUMBER(5,0);
BEGIN
SELECT ACCOUNTS.ACCOUNT_NUMBER FROM INSERTED INTO TEMP_1
OPEN ACCOUNTS_CUR;
INSERT
INTO TRANSACTIONS VALUES
(
SYSDATE,
- :NEW.ACCOUNT_NUMBER,
'NEW ACCOUNT',
0
);
CLOSE ACCOUNTS_CUR;
END ACCOUNTS_TRANSCATION_TRIG_1;
CREATE TABLE accounts(
ACCOUNT_NUMBER number,
ACCOUNT_NAME varchar2(20)
);
CREATE SEQUENCE ACCOUNT_NO_SEQ;
CREATE OR REPLACE TRIGGER ACCOUNT_NUMBER_TRIG
BEFORE INSERT
ON ACCOUNTS
FOR EACH ROW
WHEN (NEW.ACCOUNT_NUMBER is not null)
BEGIN
:NEW.ACCOUNT_NUMBER :=ACCOUNT_NO_SEQ.nextvaL;
END ACCOUNT_NUMBER_TRIG;
/
CREATE TABLE transactions(
TR_DATE date,
TR_ACCOUNT_NUMBER number,
TR_TYPE varchar2(20),
TR_somenumber int
);
CREATE OR REPLACE TRIGGER ACCOUNTS_TRANSCATION_TRIG_1 AFTER
INSERT ON ACCOUNTS FOR EACH ROW
BEGIN
INSERT INTO TRANSACTIONS( TR_DATE, TR_ACCOUNT_NUMBER, TR_TYPE, TR_somenumber )
VALUES
(
SYSDATE,
:NEW.ACCOUNT_NUMBER,
'NEW ACCOUNT',
0
);
END ACCOUNTS_TRANSCATION_TRIG_1;
/
INSERT INTO accounts( ACCOUNT_NUMBER, ACCOUNT_NAME ) VALUES (1111,'My Name' );
select * from accounts;
ACCOUNT_NUMBER ACCOUNT_NAME
-------------- --------------------
2 My Name
select * from transactions;
TR_DATE TR_ACCOUNT_NUMBER TR_TYPE TR_SOMENUMBER
---------- ----------------- -------------------- -------------
2017/07/11 2 NEW ACCOUNT 0
You can use CURVAL to get the most recent value returned by NEXTVAL:
CREATE OR REPLACE TRIGGER ACCOUNTS_TRANSCATION_TRIG_1 AFTER
INSERT ON ACCOUNTS FOR EACH ROW DECLARE CURSOR ACCOUNTS_CUR IS
BEGIN
INSERT
INTO TRANSACTIONS VALUES
(
SYSDATE,
- ACCOUNT_NO_SEQ.curval,
'NEW ACCOUNT',
0
);
CLOSE ACCOUNTS_CUR;
END ACCOUNTS_TRANSCATION_TRIG_1;
However in this case there is no need, as it has been used to set the ACOUNT_NUMBER:
INSERT
INTO TRANSACTIONS VALUES
(
SYSDATE,
- :NEW.ACCOUNT_NUMBER,
'NEW ACCOUNT',
0
);
BTW unless you are on an old version of Oracle this should work for first trigger:
CREATE OR REPLACE TRIGGER ACCOUNT_NUMBER_TRIG
BEFORE INSERT
ON ACCOUNTS
FOR EACH ROW
WHEN (NEW.ACCOUNT_NUMBER is not null)
BEGIN
:NEW.ACCOUNT_NUMBER := ACCOUNT_NO_SEQ.nextvaL;
END ACCOUNT_NUMBER_TRIG;
(I suspect the WHEN clause is wrong - should be when is null?)

SQL: Stored procedure

I am implementing a library management system in SQL. I have the following table structure and some values inserted in them:
create table books
(
IdBook number(5),
NameBook varchar2(35),
primary key(IdBook)
);
create table users
(
IdUsers number(5),
NameUser varchar2(20),
primary key(IdUsers)
);
create table borrowed
(
IdBorrowed number(5),
IdUsers number(5),
IdBook number(5),
DueDate date,
DateReturned date,
constraint fk_borrowed foreign key(IdUsers) references users(IdUsers),
constraint fk_borrowed2 foreign key(IdBook) references books(IdBook)
);
insert into books values(0,'FairyTale');
insert into books values(1,'Crime and Punishment');
insert into books values(2,'Anna Karenina');
insert into books values(3,'Norwegian Wood');
insert into users values(01,'Robb Dora');
insert into users values(02,'Pop Alina');
insert into users values(03,'Grozavescu Teodor');
insert into users values(04,'Popa Alin');
insert into borrowed values(10,02,3,'22-Jan-2017',null);
insert into borrowed values(11,01,1,'25-Jan-2017','19-Dec-2016');
insert into borrowed values(12,01,3,'22-Jan-2017',null);
insert into borrowed values(13,04,2,'22-Jan-2017','13-Dec-2016');
What I want now is that my db to allow "borrowing" books for the users(i.e insert into the borrowed table) that have no unreturned books(i.e date returned is not null) and if they have unreturned books I want to abandon the whole process. I thought to implement this in the following way:
create or replace procedure borrowBook(IdBorrowed in number,IdUsers number,IdBook number,DueDate date,DateReturned date) as begin
if exists (SELECT u.IdUsers, u.NameUser, b.DateReturned
FROM users u, borrowed b
WHERE u.IDUSERS = b.IdUsers and DateReturned is not null),
insert into borrowed values(IdBorrowed,IdUsers,IdBook,DueDate,DateReturned);
end borrowBook;
The above procedure does not check if the parameter I pass to this function is the same as the one in my select and I do not know how to do this and correctly insert a value in my table.
Any help would be much appreciated. Thank in advance!
You should not name your parameters the same as columns also used inside the procedure.
You can also simplify your procedure to a single INSERT statement, no IF required:
create or replace procedure borrowBook(p_idborrowed in number, p_idusers number, p_idbook number, p_duedate date, p_datereturned date)
as
begin
insert into borrowed (idborrowed, idusers, idbook, duedate, datereturned)
select p_idborrowed, p_idusers, p_idbook, p_duedate, p_datereturned
from dual
where not exists (select *
from users u
join borrowed b on u.idusers = b.idusers
and b.datereturned is not null);
end borrowBook;
It's also good coding style to explicitly list the columns for an INSERT statement. And you should get used to the explicit JOIN operator instead of using implicit joins in the where clause.
What about this one:
create or replace procedure borrowBook( p_IdBorrowed in number ,
p_IdUsers number ,
p_IdBook number ,
p_DueDate date ,
p_DateReturned date )
as
begin
if (SELECT COUNT(*)
FROM borrowed
WHERE IDUSERS = p_IdUsers
AND DateReturned IS NULL) = 0 THEN
insert into borrowed values (p_IdBorrowed ,
p_IdUsers ,
p_IdBook ,
p_DueDate ,
p_DateReturned );
end if ;
end borrowBook;
You would seem to want something like this:
create or replace procedure borrowBook (
in_IdBorrowed in number,
in_IdUsers number,
in_IdBook number,
in_DueDate date,
in_DateReturned date
) as
v_flag number;
begin
select (case when exists (select 1
from borrowed b
where b.IdUsers = in_IdUsers and b.DateReturned is not null
)
then 1 else 0
end)
into v_flag
from dual;
if (flag = 0) then
insert into borrowed
values(in_IdBorrowed, in_IdUsers, in_IdBook, in_DueDate, v_DateReturned);
end if
end -- borrowBook;

Get ID of last inserted row and use it to insert into another table in a stored procedure

I have the following stored procedure which we use to insert data into a table:
CREATE OR REPLACE PROCEDURE mySproc
(
invoiceId IN NUMBER
customerId IN NUMBER
)
IS
BEGIN
INSERT INTO myTable (INVOICE_ID)
VALUES (invoiceId);
END mySproc;
/
What I am trying to do is to get the last inserted ID (this is the primary key field on myTable and auto incremented using a sequence) and insert it into another table, I have tried the following but could not get it working:
CREATE OR REPLACE PROCEDURE mySproc
(
invoiceId IN NUMBER
customerId IN NUMBER
)
IS
BEGIN
INSERT INTO myTable (INVOICE_ID)
VALUES (invoiceId)
returning id into v_id;
INSERT INTO anotherTable (ID, customerID)
VALUES (v_id, customerId);
END mySproc;
/
I am getting this error: [Error] PLS-00049 (59: 26): PLS-00049: bad bind variable 'V_ID' I think I need to declare v_id somewhere but I tried before and after the BEGIN statement but that gave another error.
Any ideas as to how to do this?
Thanks
Change your procedure to
CREATE OR REPLACE PROCEDURE mySproc
(
invoiceId IN NUMBER, -- Added comma
customerId IN NUMBER
)
IS
v_id NUMBER; -- ADDED
BEGIN
INSERT INTO myTable (INVOICE_ID)
VALUES (invoiceId)
returning id into v_id;
INSERT INTO anotherTable (ID, customerID)
VALUES (v_id, customerId);
END mySproc;
Share and enjoy.