How do I modify the values of a collection inside a table? - oracle

Basically, given a table with the below structure, I want to add a city at the end of a list of cities so that it'll be visited last in a trip with a number/id input by keyboard.
CREATE TYPE type_cities IS VARRAY(101) of varchar2(12);
CREATE TABLE trip(
trip NUMBER(4),
name VARCHAR2(20),
cities type_cities,
status varchar2(12)
);
declare
nrTrip number(4) := &nr;
name_city varchar2(12) := &namecity;
number_last number(4);
begin
number_last = trip(nrTrip).cities.count();
trip(nrTrip).cities.extend();
select name_city into trip(nrTrip).cities(number_last+1);
end;
I don't know the syntax neccessary to do this (and I'd ask why it doesn't work if that's alright, it didn't work with
trip(nrTrip).cities(number_last+1) := name_city
either)

Here's one option: fetch the row first, update it (i.e. add a new city into the array), update the table.
Type and table:
SQL> CREATE TYPE type_cities IS VARRAY(101) of varchar2(12);
2 /
Type created.
SQL> CREATE TABLE trip(
2 trip NUMBER(4),
3 name VARCHAR2(20),
4 cities type_cities,
5 status varchar2(12)
6 );
Table created.
Initial record (otherwise, there's nothing to update):
SQL> insert into trip (trip, name, cities, status)
2 values (1, 'Test', type_cities('London'), 'OK');
1 row created.
Procedure:
SQL> declare
2 nrTrip number(4) := &nr;
3 l_row trip%rowtype;
4 name_city varchar2(12) := '&namecity';
5 number_last number(4);
6 begin
7 select *
8 into l_row
9 from trip
10 where trip = nrTrip;
11
12 number_last := l_row.cities.count;
13
14 l_row.cities.extend;
15 l_row.cities(number_last + 1) := name_city;
16
17 update trip set cities = l_row.cities
18 where trip = nrTrip;
19 end;
20 /
Enter value for nr: 1
Enter value for namecity: Zagreb
PL/SQL procedure successfully completed.
Result:
SQL> select * from trip;
TRIP NAME CITIES STATUS
---------- -------------------- ----------------------------------- ------------
1 Test TYPE_CITIES('London', 'Zagreb') OK
--------
SQL> here it is

Related

How can i correct this error(The package is configured with translation errors)?

This is the question
-Create customers table and add these columns:
Id
Name
AGE
ADDRESS
SALARY
-Add 10 rows.
-Create a package with three procedures:
one that add a customer to the table.
one that removes a customer from the table.
one that lists all the customers.
-Create customers table and add these columns:
Id
Name
AGE
ADDRESS
SALARY
-Add 10 rows.
-Create a package with three procedures:
one that add a customer to the table.
one that removes a customer from the table.
one that lists all the customers.
CREATE TABLE customer(
customer_id NUMBER NOT NULL,
customer_name VARCHAR2(50) NOT NULL,
customer_age NUMBER NOT NULL,
customer_address VARCHAR2(50) NOT NULL,
customer_salary NUMBER NOT NULL,
PRIMARY KEY(customer_id)
);
INSERT INTO customer
VALUES
(1,'Ahemed',22,'wq1',2500);
INSERT INTO customer
VALUES
(2,'salem',24,'wq2',2000);
INSERT INTO customer
VALUES
(3,'Aboud',26,'wq3',2200);
INSERT INTO customer
VALUES
(4,'Tarek',27,'wq4',2100);
INSERT INTO customer
VALUES
(5,'Hazem',33,'wq5',3000);
INSERT INTO customer
VALUES
(6,'Hayder',32,'wq6',2300);
INSERT INTO customer
VALUES
(7, 'Sammy',35,'wq7',2700);
INSERT INTO customer
VALUES
(8,'Mohammed',20,'wq8',4000);
INSERT INTO customer
VALUES
(9,'Tayseer',18,'wq9',3600);
INSERT INTO customer
VALUES
(10,'Hamoud',40,'wq10',3100);
CREATE OR REPLACE PACKAGE mypackage AS
PROCEDURE add_customer(c_id customer.customer_id%type,
c_name customer.customer_name%type,
c_age customer.customer_age%type,
c_address customer.customer_address%type,
c_salary customer.customer_salary%type);
PROCEDURE remove_customer(c_id customer.customer_id%type);
PROCEDURE list_customer;
END mypackage ;
CREATE OR REPLACE PACKAGE BODY mypackage AS
PROCEDURE add_customer(c_id customer.customer_id%type,
c_name customer.customer_name%type,
c_age customer.customer_age%type,
c_address customers.address%type,
c_salary customer.customer_salary%type)
IS
BEGIN
INSERT INTO customer (customer_id ,customer_name,customer_age ,customer_address ,customer_salary)
VALUES(c_id, c_name, c_age, c_address, c_salary);
END add_customer;
PROCEDURE remove_customer(c_id customer.customer_id%type) IS
BEGIN
DELETE FROM customer
WHERE customer_id= c_id;
END remove_customer;
PROCEDURE list_customer(customer_id ,customer_name,customer_age ,customer_address ,customer_salar) IS
BEGIN
select * from customer;
END list_customer;
If i create this package the error is(The package is configured with translation errors) how can i solve it?
Table and package specification are OK (kind of):
SQL> CREATE TABLE customer(
2 customer_id NUMBER NOT NULL,
3 customer_name VARCHAR2(50) NOT NULL,
4 customer_age NUMBER NOT NULL,
5 customer_address VARCHAR2(50) NOT NULL,
6 customer_salary NUMBER NOT NULL,
7 PRIMARY KEY(customer_id)
8 );
Table created.
SQL> CREATE OR REPLACE PACKAGE mypackage AS
2 PROCEDURE add_customer(c_id customer.customer_id%type,
3 c_name customer.customer_name%type,
4 c_age customer.customer_age%type,
5 c_address customer.customer_address%type,
6 c_salary customer.customer_salary%type);
7
8 PROCEDURE remove_customer(c_id customer.customer_id%type);
9 PROCEDURE list_customer;
10 END mypackage ;
11 /
Package created.
But then, for some reason, you didn't follow the same recipe for package body:
SQL> CREATE OR REPLACE PACKAGE BODY mypackage AS
2 PROCEDURE add_customer(c_id customer.customer_id%type,
3 c_name customer.customer_name%type,
4 c_age customer.customer_age%type,
5 c_address customers.address%type,
6 c_salary customer.customer_salary%type)
7 IS
8 BEGIN
9 INSERT INTO customer (customer_id ,customer_name,customer_age ,customer_address ,customer_salary)
10 VALUES(c_id, c_name, c_age, c_address, c_salary);
11 END add_customer;
12
13 PROCEDURE remove_customer(c_id customer.customer_id%type) IS
14 BEGIN
15 DELETE FROM customer
16 WHERE customer_id= c_id;
17 END remove_customer;
18
19 PROCEDURE list_customer(customer_id ,customer_name,customer_age ,customer_address ,customer_salar) IS
20 BEGIN
21 select * from customer;
22 END list_customer;
23 end mypackage;
24 /
Warning: Package Body created with compilation errors.
What's wrong?
SQL> show err
Errors for PACKAGE BODY MYPACKAGE:
LINE/COL ERROR
-------- -----------------------------------------------------------------
19/41 PLS-00103: Encountered the symbol "," when expecting one of the
following:
in out <an identifier> <a double-quoted delimited-identifier>
table ... columns long double ref char standard time
timestamp interval date binary national character nchar
20/4 PLS-00103: Encountered the symbol "BEGIN" when expecting one of
the following:
not null of nan infinite dangling a empty json
SQL>
Line #19 is wrong:
19 PROCEDURE list_customer(customer_id ,customer_name,customer_age ,customer_address ,customer_salar) IS
So: if - apparently - you do know how to use parameters while declaring procedures, why didn't you do the same for list_customer? Besides, it wouldn't work anyway - in PL/SQL, a SELECT must have an INTO (and your procedure doesn't). I guess that at customer_id should be passed as a parameter (so I'm doing that in my example).
Moreover, all procedures you declare in package specification must exist in package body, with exactly the same description (you've used customer.address%type but that column doesn't exist in the table).
So, when fixed: specification:
SQL> CREATE OR REPLACE PACKAGE mypackage AS
2 PROCEDURE add_customer(c_id customer.customer_id%type,
3 c_name customer.customer_name%type,
4 c_age customer.customer_age%type,
5 c_address customer.customer_address%type,
6 c_salary customer.customer_salary%type);
7
8 PROCEDURE remove_customer(c_id customer.customer_id%type);
9 PROCEDURE list_customer (p_customer_id customer.customer_id%type);
10 END mypackage ;
11 /
Package created.
Body:
SQL> CREATE OR REPLACE PACKAGE BODY mypackage AS
2 PROCEDURE add_customer(c_id customer.customer_id%type,
3 c_name customer.customer_name%type,
4 c_age customer.customer_age%type,
5 c_address customer.customer_address%type,
6 c_salary customer.customer_salary%type)
7 IS
8 BEGIN
9 INSERT INTO customer (customer_id ,customer_name,customer_age ,customer_address ,customer_salary)
10 VALUES(c_id, c_name, c_age, c_address, c_salary);
11 END add_customer;
12
13 PROCEDURE remove_customer(c_id customer.customer_id%type) IS
14 BEGIN
15 DELETE FROM customer
16 WHERE customer_id= c_id;
17 END remove_customer;
18
19 PROCEDURE list_customer(p_customer_id in customer.customer_id%type)
20 --,customer_name,customer_age ,customer_address ,customer_salar) IS
21 is
22 l_row customer%rowtype;
23 BEGIN
24 select * into l_row from customer where customer_id = p_customer_id;
25 END list_customer;
26 end mypackage;
27 /
Package body created.
SQL>
This, at least, compiles. Does it do what you wanted it, I didn't try - I'll leave it to you.

limit the amount of trigger updates for a specific row in oracle

I want to audit update changes in a specific table, and for that I've created a trigger that tracks every time a row is updated, it then write the updated changes into a new historical table:
create table test (id number generated always as identity,name varchar2(10) default null, school varchar2(10) null);
insert into test (name,school) values ('John','MIT');
insert into test (name,school) values ('Max','Oxford');
create table test_history (id int,name varchar2(10), school varchar2(10));
create or replace trigger test_trigger
after update
of name,school
on test
for each row
begin
insert into test_history
values
(
:old.id,
:new.name,
:new.school
);
end;
/
What I would like to do is to limit the amount a specific row is updated to a certain value. For example, the following update statement can only be executed 10 times:
update test
set
name = 'Jason'
where id = 1;
In this way if I execute the above statement 10 times it should work, but if the execution happens the 11th time it should fail. So the maximum amount of rows of a specific unique id is 10.
Count number of rows in the history table and raise an error if it exceeds value you find appropriate.
SQL> create or replace trigger test_trigger
2 after update
3 of name,school
4 on test
5 for each row
6 declare
7 l_cnt number;
8 begin
9 select count(*) into l_cnt
10 from test_history
11 where id = :new.id;
12
13 if l_cnt <= 10 then
14 insert into test_history
15 values
16 (
17 :old.id,
18 :new.name,
19 :new.school
20 );
21 else
22 raise_application_error(-20000, 'Too many updates');
23 end if;
24 end;
25 /
Trigger created.
Update:
SQL> update test set name = 'Jason' where id = 1;
1 row updated.
<snip>
SQL> update test set name = 'Jason' where id = 1;
1 row updated.
SQL> update test set name = 'Jason' where id = 1;
update test set name = 'Jason' where id = 1
*
ERROR at line 1:
ORA-20000: Too many updates
ORA-06512: at "SCOTT.TEST_TRIGGER", line 17
ORA-04088: error during execution of trigger 'SCOTT.TEST_TRIGGER'
SQL>

PL/SQL CURRENT_DATE if NULL

I need some help for figuring out how to use the CURRENT_DATE if the p_start_time is NULL when doing an insert.
The code below is what I have figured out so far (except for the insert statement). The code I need help for is the last code block.
Using PL/SQL btw.
create or replace procedure BEGIN_TRIP_SP (
p_trip_id OUT INTEGER, -- an output parameter
p_bicycle_id IN INTEGER, -- Must not be NULL. Must match value value in BC_BICYCLE and BC_DOCK tables.
p_start_time IN DATE, -- If NULL, use CURRENT_DATE system date value
p_membership_id IN INTEGER -- Must not be NULL. Must match value in BC_MEMBERSHIP table.
)
IS
lv_membership_id_exist INTEGER;
lv_bicycle_id_exist INTEGER;
lv_Error_Message VARCHAR2(200);
ex_Exception EXCEPTION;
BEGIN
IF p_bicycle_id IS NULL THEN
lv_Error_Message := 'Missing mandatory value for bicycle id in BEGIN_TRIP_SP. No trip added.';
RAISE ex_Exception;
END IF;
IF p_start_time IS NULL THEN
NVL(trip_start_time, '08-03-2022')
END IF;
INSERT INTO bc_trip (
Trip_id,
Bicycle_id,
Trip_start_time,
Membership_id
)
VALUES (
p_trip_id,
p_bicycle_id,
NVL(p_start_time, current_date),
p_membership_id
);
See if this helps; I presumed trip_id is somehow automatically generated so you'll be just returning its value to the caller.
Sample table:
SQL> CREATE TABLE bc_trip
2 (
3 trip_id NUMBER GENERATED ALWAYS AS IDENTITY,
4 bicycle_id NUMBER,
5 trip_start_time DATE,
6 membership_id NUMBER
7 );
Table created.
Procedure:
SQL> CREATE OR REPLACE PROCEDURE begin_trip_sp
2 (p_trip_id OUT INTEGER, -- an output parameter
3 p_bicycle_id IN INTEGER, -- Must not be NULL. Must match value value in BC_BICYCLE and BC_DOCK tables.
4 p_start_time IN DATE, -- If NULL, use CURRENT_DATE system date value
5 p_membership_id IN INTEGER -- Must not be NULL. Must match value in BC_MEMBERSHIP table.
6 )
7 IS
8 BEGIN
9 IF p_bicycle_id IS NULL
10 THEN
11 raise_application_error (
12 -20000,
13 'Missing mandatory value for bicycle id in BEGIN_TRIP_SP. No trip added.');
14 ELSE
15 INSERT INTO bc_trip (bicycle_id, trip_start_time, membership_id)
16 VALUES (p_bicycle_id,
17 NVL (p_start_time, CURRENT_DATE),
18 p_membership_id)
19 RETURNING trip_id
20 INTO p_trip_id;
21 END IF;
22 END;
23 /
Procedure created.
Testing:
SQL> SET SERVEROUTPUT ON
SQL> DECLARE
2 l_trip_id NUMBER;
3 BEGIN
4 begin_trip_sp (l_trip_id,
5 1,
6 NULL,
7 100);
8 DBMS_OUTPUT.put_line ('Inserted trip ID = ' || l_trip_id);
9 END;
10 /
Inserted trip ID = 1
PL/SQL procedure successfully completed.
What if there's no P_BICYCLE_ID?
SQL> l5
5* 1,
SQL> c/1/null/
5* null,
SQL> /
DECLARE
*
ERROR at line 1:
ORA-20000: Missing mandatory value for bicycle id in BEGIN_TRIP_SP. No trip
added.
ORA-06512: at "DP_4005.BEGIN_TRIP_SP", line 11
ORA-06512: at line 4
SQL>
Result is
SQL> SELECT * FROM bc_trip;
TRIP_ID BICYCLE_ID TRIP_START MEMBERSHIP_ID
---------- ---------- ---------- -------------
1 1 08.03.2022 100
SQL>
Just write default value for that parameter:
create or replace procedure BEGIN_TRIP_SP (
p_trip_id OUT INTEGER,
p_bicycle_id IN INTEGER,
p_start_time IN DATE DEFAULT sysdate,--if the parameter is not given it will take sysdate (current date)
p_membership_id IN INTEGER
)...

Keep getting compilation error while creating the following procedure

Create a procedure named 'select_city' which accepts one input parameter user_id of type number and one output parameter city_details of type varchar. This procedure is used to display the city_details of user.If the user is from bangalore then display the city_details as 'User is from Bangalore',or if the user is from chennai then display the city_details as 'User is from Chennai', else display the city_details as 'User is from other cities'.
CREATE PROCEDURE select_city ( user_id IN user_details.id%type,
city_details OUT VARCHAR2(255) )
AS
BEGIN
SELECT CASE
WHEN city = 'Bangalore' THEN 'User is from Bangalore'
WHEN city = 'Chennai' THEN 'User is from Chennai'
ELSE 'User is from other cities'
END tmp_status INTO city_details
FROM contact cnt
WHERE cnt.id = user_id;
END;
OUT parameter shouldn't have size. Remove it.
Also (probably not related to error you got), consider using CREATE OR REPLACE because any subsequent CREATE will fail as the procedure - although invalid - already exists so you'd have to drop it first.
Sample table:
SQL> create table contact as
2 select 'Bangalore' city, 1 id from dual;
Table created.
Procedure:
SQL> create or replace procedure select_city
2 (user_id in number,
3 city_details out varchar2 --> no size here
4 )
5 as
6 begin
7 select case
8 when city = 'Bangalore' then
9 'User is from Bangalore'
10 when city = 'Chennai' then
11 'User is from Chennai'
12 else
13 'User is from other cities'
14 end tmp_status
15 into city_details
16 from contact cnt
17 where cnt.id = user_id;
18 end;
19 /
Procedure created.
Testing:
SQL> set serveroutput on;
SQL> declare
2 l_citydet varchar2(255);
3 begin
4 select_city(1, l_citydet);
5 dbms_output.put_line(l_citydet);
6 end;
7 /
User is from Bangalore
PL/SQL procedure successfully completed.
SQL>

PL/SQL procedures same row

Table before solve:
ID NAME DATA
1 zhang 9
1 zhang 12
2 wang 1
2 wang 2
/this is the table before solved/
Table after solve:
ID NAME DATA
1 DIY 13
2 DIY 3
/this is what I want to get result/
There is the procedure:
update A a
set a.date=(select max(f_get(f.id,f.date,g.date))
from A f,A g
where f.date!=g.date
and f.id=a.id);
--function f_get()
create or replace function f_get
(id in varchar2,date in varchar,date2 in varchar )
return varchar is
Result varchar
date3 varchar(4);
begin
select nvl(date,date2) into date3
from dual;
Result:=date3;
delete from A a
where a.ID=id
and a.date=date2;--there is error
return(Result);
end f_get;
Your question does its best to hide itself, but this is the point:
"--there is error "
The error you get is (presumably) ORA-14551: cannot perform a DML operation inside a query, which you are getting because you are calling a FUNCTION which includes a DELETE command from a SELECT statement.
Oracle's transactional model doesn't allow queries to change the state of the database. Instead of a FUNCTION you need to write a procedure.
Although, if you want to remove duplicate rows, a straight SQL solution will suffice. Something like
delete from a
where (id, date) not in
( select id, max(date) from a
group by id)
/
You really should pay attention how to write questions. It would help us to help you. This is my guess what you are looking for. Unfortunately I don't have 9i available, but hope this helps !
create table so7t (
id number,
name varchar2(10),
data number -- date is a reserved word and can't be used as identifier
);
-- 1001
insert into so7t values (1, 'zhang', 9);
-- 1100
insert into so7t values (1, 'zhang', 12);
-- 0001
insert into so7t values (2, 'wang', 1);
-- 0010
insert into so7t values (2, 'wang', 2);
select * from so7t;
/* from http://www.dbsnaps.com/oracle/bitwise-operators-in-oracle/ */
create or replace function bitor (x number, y number)
return number
is
begin
return (x+y)-bitand(x,y);
end;
/
show errors
create or replace procedure solve (
p_id in number
) as
type ids_t is table of number;
v_ids ids_t;
v_result number := 0;
begin
select data bulk collect into v_ids from so7t where id = p_id;
for i in v_ids.first .. v_ids.last loop
v_result := bitor(v_result, v_ids(i));
end loop;
delete from so7t where id = p_id;
insert into so7t values (p_id, 'DIY', v_result);
end;
/
begin
solve(1);
commit;
solve(2);
commit;
end;
/
Table before solve:
ID NAME DATA
---------- ---------- ----------
1 zhang 9
1 zhang 12
2 wang 1
2 wang 2
Table after solve:
ID NAME DATA
---------- ---------- ----------
1 DIY 13
2 DIY 3

Resources