PL/SQL Oracle: access new values in a before insert trigger - plsql

Facing the following error:
[Error] PLS-00049 (12: 11): PLS-00049: bad bind variable 'NEW.OPTION_D'
I am trying to execute the following:
create or replace trigger check_option_for_stage
before insert on lot_option
for each row
when (new.stage_id > 0 and new.option_id > 0)
declare
not_existing_option exception;
num_count number;
begin
select count(*) into num_count
from option_cost os
where :new.option_id = os.option_id and :new.stage_id = os.stage_id;
if num_count = 1 then
DBMS_OUTPUT.PUT_LINE('The option can be applied to the lot at the current stage');
ELSE
raise not_existing_option;
end if;
exception
when not_existing_option then
DBMS_OUTPUT.PUT_LINE('The option is not available on this stage, therefore rejected');
when others then
DBMS_OUTPUT.PUT_LINE('Oops!, something went wrong, it needs your attention!');
end;
/
Why am I facing this? Why is it a bad bind variable? I know that I should be able to access the new values by typing :new.whateverthecolumnname
I am using Oracle 11g.
The definition of the table I am playing around
SQL> desc option_cost
Name Null? Type
----------------------------------------- -------- ----------------------------
COST NOT NULL NUMBER
OPTION_ID NOT NULL NUMBER(38)
STAGE_ID NOT NULL NUMBER(38)
SQL> desc lot_option;
Name Null? Type
----------------------------------------- -------- ----------------------------
LOT_ID NOT NULL NUMBER(38)
OPTION_ID NOT NULL NUMBER(38)
COST NOT NULL NUMBER
DATE_CREATED DATE
STAGE_ID NOT NULL NUMBER(38)

Is the column option_id (with an id at the end) or just option_d (with no i)? option_id would seem to make more sense. Assuming option_id is correct, you have a typo in your SELECT statement where you are missing the i in id. You want something like
select count(*)
into count
from option_cost oc
where :new.option_id = oc.option_id
and :new.stage_id = oc.stage_id;
Of course, since count is a reserved word, it is not a good idea to declare a local variable named count. It would make much more sense to name that variable, say, l_count or use some other naming convention both to identify a local variable and to avoid using a reserved word.

Related

PLSQL NULL or Empty collection in table SELECT

I am trying to figure out a clean way of qualifying on a table type that may be null or empty. Below is what I have tried so far but that results in a
ORA-01427: single-row subquery returns more than one row
DECLARE
V_TEMP_IDS V500.T_TEMP_IDS := V500.T_TEMP_IDS(123, 124);
TYPE T_RESULTS IS TABLE OF NUMBER;
V_RESULTS T_RESULTS;
BEGIN
SELECT TEMP_ID BULK COLLECT INTO V_RESULTS FROM PEOPLE
WHERE ACTIVE = 1
AND TEMP_ID IN (COALESCE(NULLIF((SELECT * FROM TABLE(V_TEMP_IDS)), 0), TEMP_ID));
dbms_output.put_line(SQL%ROWCOUNT);
END;
I would like to select all rows if the collection is null or empty but if it has entries, such as in this example, to include them in the qualification. Hope that makes sense!
Thanks in advance!
NULLIF((SELECT * FROM TABLE(V_TEMP_IDS)), 0) -- is not allowed.
If SELECT * FROM TABLE(V_TEMP_IDS) returns multiple rows, nullif won't work.
(SELECT NULLIF(*, 0) FROM TABLE(V_TEMP_IDS)) -- should be what you want to do..
If you want to check whether v_temp_ids is null or empty, use the is null and is empty operators:
declare
v_temp_ids t_temp_ids := t_temp_ids(123, 124);
type t_results is table of number;
v_results t_results;
begin
select temp_id bulk collect into v_results from people
where active = 1
and ( temp_id member of v_temp_ids
or v_temp_ids is empty
or v_temp_ids is null );
dbms_output.put_line(sql%rowcount);
end;
Test a null collection with
v_temp_ids t_temp_ids;
Test an empty collection with
v_temp_ids t_temp_ids := t_temp_ids();

How to use a bind variable in trigger body?

I'm new to PL/SQL. I'm using oracle 11g XE along with sql developer. I'm trying to create to create an after insert trigger as follows
create or replace trigger tr1
after
insert ON
employee
for each row
begin
print :new.emp_id;
end;
The employee table is as follows
create table employee
( emp_id varchar2(5) primary key,
emp_name varchar2(10),
salary number,
company varchar2(10) foreign key references companies(comp_name)
);
When I run the statement I got a 'enter binds' window for the bind variable :new. But I was confused that why do I need to enter the value for :new since it is pseudorecord. Then I entered 'employee' as the values for :new. Now I'm getting the following error.
Error(2,8): PLS-00103: Encountered the symbol "" when expecting one of the following: := . ( # % ; The symbol ":=" was substituted for "" to continue.
Your problem is not in the :new pseudorecord. The error is coming from the usage of print, which is used to print the bind variable used in successful PL/SQL block or used in an EXECUTE command. For example, you can use it this way:
VARIABLE n NUMBER
BEGIN
:n := 1;
END;
/
Then
PRINT n;
But if you want to test the value being inserted, you can use DBMS_OUTPUT.PUT_LINE like this:
create or replace trigger tr1
after
insert ON
employee
for each row
BEGIN
dbms_output.put_line(:new.emp_id);
END;
/
Enable DBMS_OUTPUT window in your SQL Developer, then run
insert into employee values(1, 'empName', 1000, 'ABC');
You'll see 1 printed out.
However, you can always test the value from the table. Because the value should be already inserted into table. You can just query.

Execute stored procedure error in select statement

I have a Procedure like this,
create or replace
PROCEDURE SP_PROOF
( proof_id IN NUMBER
, Type1 IN VARCHAR2
, StatementType IN NUMBER
, Resultset OUT NUMBER
) AS
BEGIN
IF StatementType = 1 Then
INSERT INTO ID_Proof (proofid,Id_type)
VALUES (proof_id, Type1);
ELSIF StatementType=2 THEN
SELECT proofid,Id_type Into Resultset FROM ID_Proof;
ELSIF StatementType=3 THEN
UPDATE ID_Proof SET Id_type = Type1 WHERE proofid = proof_id;
ELSIF StatementType=4 THEN
DELETE FROM ID_Proof WHERE proofid = proof_id;
end if;
end;
Im getting an error like this,
Error(14,1): PL/SQL: SQL Statement ignored
Error(14,64): PL/SQL: ORA-00947: not enough values
Please help me to correct the error.
Line 14 is:
SELECT proofid,Id_type Into Resultset FROM ID_Proof;
You are selecting two values, proofid and Id_type, into a single scalar variable Resultset. But you also have no filter, so even if you changed that to select a single value then you'd get a too-many-rows error if there was more than one row in the table (and no-data-found if the table is empty).
It isn't clear what you want to happen; perhaps you want select id_type into resultset from id_proof, but from the parameters id_type is a string - so selecting that into a number variable is likely to fail too. Or perhaps you want all IDs for the specified type, in which case the type of result set would need to be a table type or a ref cursor.
Having separate procedures and functions would be probably be clearer, too.

pl /sql procedure execution giving an error

My stored proc is defined as
create or replace procedure TEST(
name IN table1.col_name%type,
price IN table1.col_price%type
)
is
begin
update table1 t set t.name =name where t.price = price;
commit;
end TEST;
I am trying to execute it as
exec TEST(name => 'John', price => 1000);
However, it gives invalid SQL error. What am i missing here?
Your input parameter %type statements claim the column names are col_name and col_price. But that is not how you refer to them in your stored procedure (name and price).
Bad things can happen when you name variables after column names. AskTom recommends a limited convention of variable naming conventions:
local variables start with L_
parameters start with P_
global package variables start with G_
That link has a good general discussion on PL/SQL naming conventions. I personally just use V_ for most variables (aside from indexes and other obvious things), but that's just me.
Lastly, the col_ in the column names seem redundant; simply use name and price as column names.
So, that said, I think this does what you want:
create table table1 (
name varchar2(30),
price number
);
create or replace procedure TEST(
p_name IN table1.name%type,
p_price IN table1.price%type
)
is
begin
update table1
set name = p_name
where price = p_price;
commit;
end TEST;
/
insert into table1 values ('John', 500);
commit;
select * from table1;
exec TEST(p_name => 'Bob', p_price => 500);
select * from table1;
-- Clean up test artifacts
drop procedure test;
drop table table1;
Giving the output:
table TABLE1 created.
PROCEDURE TEST compiled
1 rows inserted.
committed.
NAME PRICE
------------------------------ ----------
John 500
anonymous block completed
NAME PRICE
------------------------------ ----------
Bob 500
procedure TEST dropped.
table TABLE1 dropped.
I really don't understand the variable prefixing approach. Oracle don't do it with their own API's, and it would be extraordinarily irritating if they did. It always seems like a workaround, rather than a fix.
For me the fix is to namespace the variables with the procedure name. It keeps the argument names "clean" and makes your code 100% proof against capture:
create or replace procedure TEST(
name IN table1.col_name%type,
price IN table1.col_price%type)
is
begin
update table1 t
set name = test.name
where t.price = price;
commit;
end TEST;
Lots more info on capture here.

Modify a column to NULL - Oracle

I have a table named CUSTOMER, with few columns. One of them is Customer_ID.
Initially Customer_ID column WILL NOT accept NULL values.
I've made some changes from code level, so that Customer_ID column will accept NULL values by default.
Now my requirement is that, I need to again make this column to accept NULL values.
For this I've added executing the below query:
ALTER TABLE Customer MODIFY Customer_ID nvarchar2(20) NULL
I'm getting the following error:
ORA-01451 error, the column already allows null entries so
therefore cannot be modified
This is because already I've made the Customer_ID column to accept NULL values.
Is there a way to check if the column will accept NULL values before executing the above query...??
You can use the column NULLABLE in USER_TAB_COLUMNS. This tells you whether the column allows nulls using a binary Y/N flag.
If you wanted to put this in a script you could do something like:
declare
l_null user_tab_columns.nullable%type;
begin
select nullable into l_null
from user_tab_columns
where table_name = 'CUSTOMER'
and column_name = 'CUSTOMER_ID';
if l_null = 'N' then
execute immediate 'ALTER TABLE Customer
MODIFY (Customer_ID nvarchar2(20) NULL)';
end if;
end;
It's best not to use dynamic SQL in order to alter tables. Do it manually and be sure to double check everything first.
Or you can just ignore the error:
declare
already_null exception;
pragma exception_init (already_null , -01451);
begin
execute immediate 'alter table <TABLE> modify(<COLUMN> null)';
exception when already_null then null;
end;
/
You might encounter this error when you have previously provided a DEFAULT ON NULL value for the NOT NULL column.
If this is the case, to make the column nullable, you must also reset its default value to NULL when you modify its nullability constraint.
eg:
DEFINE table_name = your_table_name_here
DEFINE column_name = your_column_name_here;
ALTER TABLE &table_name
MODIFY (
&column_name
DEFAULT NULL
NULL
);
I did something like this, it worked fine.
Try to execute query, if any error occurs, catch SQLException.
try {
stmt.execute("ALTER TABLE Customer MODIFY Customer_ID nvarchar2(20) NULL");
} catch (SQLException sqe) {
Logger("Column to be modified to NULL is already NULL : " + sqe);
}
Is this correct way of doing?
To modify the constraints of an existing table
for example... add not null constraint to a column.
Then follow the given steps:
1) Select the table in which you want to modify changes.
2) Click on Actions.. ---> select column ----> add.
3) Now give the column name, datatype, size, etc. and click ok.
4) You will see that the column is added to the table.
5) Now click on Edit button lying on the left side of Actions button.
6) Then you will get various table modifying options.
7) Select the column from the list.
8) Select the particular column in which you want to give not null.
9) Select Cannot be null from column properties.
10) That's it.

Resources