Please help me. I am new to PL SQL. I want to Display On Screen all these details
Customer.customerNo, Customer.customerName, Customer.custBalance, customerOrder.orderDate, customerOrder.orderNo
from 2 tables [Customer, CustomerOrder]. Using the only Package with Procedure. Please help me how can I create such a package?
create or replace package my_pkg as
Procedure getAllOrders2(customer_id IN varchar2);
end my_pkg;
/
create or replace package body my_pkg as
Procedure getAllOrders2(customer_id IN varchar2) is
begin
dbms_output.put_line('customer_id is: '||customer_id );
end getAllOrders2;
end my_pkg;
/
Output Should be:
Customer Number, Customer Name, Order Number, Order Date, Customer Balance
Here is the output of all tables
One option is to use a cursor FOR loop (why? Because customer can have more than a single order, and - if you use a single select statement - you might get the too_many_rows error so you'd have to select into a collection or - as in my example - use a loop.
SQL> create or replace procedure getallorders2 (par_customer_id in customer.customerno%type)
2 is
3 begin
4 for cur_r in (select c.customerno,
5 c.customername,
6 c.custbalance,
7 o.orderdate,
8 o.orderno
9 from customer c join customerorder o
10 on c.customerno = o.customerno
11 where c.customerno = par_customer_id
12 )
13 loop
14 dbms_output.put_line
15 (cur_r.customerno ||', '||
16 cur_r.customername ||', '||
17 cur_r.custbalance ||', '||
18 cur_r.orderno ||', '||
19 to_char(cur_r.orderdate, 'dd.mm.yyyy')
20 );
21 end loop;
22 end;
23 /
Procedure created.
Testing:
SQL> set serveroutput on;
SQL> begin
2 getallorders2('A101');
3 end;
4 /
A101, basant, 32000, O101, 04.02.2021
PL/SQL procedure successfully completed.
SQL>
Now that you know how, move that code into a package body.
Related
I am trying to make a Trigger to restrict the user to performing DDL on Saturday and Sunday but if someone tries to insert data it will save that that in the weekend_action table but also raise application error that cannot perform DDL.
SQL QUERY:
create or replace trigger tgr_wkd_action
before insert
on tbl_39_dept_k
for each row
declare
begin
IF trim(TO_CHAR(sysdate,'Day')) IN ('Tuesday', 'Sunday') then
RAISE_APPLICATION_ERROR (-20000,'you cannot perform DDL on Weekend');
end if;
if inserting then
insert into user_admin.weekend_actions values
(:NEW.Dept_no,
'updation',
'user'||user||'trying to insert data on'||'_'||sysdate||'from Table tbl_39_dept_k');
end if;
end tgr_wkd_action;
if someone tries to insert data
Exactly. Insert.
Your trigger fires before update, and that's a different DML.
Apart from that:
inserts and updates are DML (data manipulation). DDL you mentioned is data definition (these are create table, alter table, ...)
weekend action vs. Tuesday? Since when is Tuesday weekend?
Perhaps you meant
SQL> CREATE OR REPLACE TRIGGER tgr_wkd_action
2 BEFORE INSERT OR UPDATE
3 ON tbl_39_dept_k
4 FOR EACH ROW
5 DECLARE
6 BEGIN
7 IF TRIM (TO_CHAR (SYSDATE, 'Day', 'nls_date_language = english')) IN
8 ('Saturday', 'Sunday')
9 THEN
10 RAISE_APPLICATION_ERROR (-20000, 'you cannot perform DML on Weekend');
11 END IF;
12
13 IF INSERTING
14 THEN
15 INSERT INTO weekend_actions
16 VALUES (
17 :NEW.Dept_no,
18 'inserting',
19 'user'
20 || USER
21 || 'trying to insert data on'
22 || '_'
23 || SYSDATE
24 || 'from Table tbl_39_dept_k');
25 ELSIF UPDATING
26 THEN
27 INSERT INTO weekend_actions
28 VALUES (
29 :NEW.Dept_no,
30 'updating',
31 'user'
32 || USER
33 || 'trying to update data on'
34 || '_'
35 || SYSDATE
36 || 'from Table tbl_39_dept_k');
37 END IF;
38 END tgr_wkd_action;
39 /
Trigger created.
SQL>
SQL> INSERT INTO tbl_39_dept_k (dept_no) VALUES (10);
1 row created.
SQL>
Tables' contents:
SQL> select * from tbl_39_dept_k;
DEPT_NO
----------
10
SQL> select * from weekend_actions;
DEPT_NO ACTION MSG
---------- ---------- ----------------------------------------------------------------------
10 inserting userSCOTTtrying to insert data on_23.11.21from Table tbl_39_dept_k
SQL>
Pretending it is weekend today (while it is Tuesday):
<snip>
7 IF TRIM (TO_CHAR (SYSDATE, 'Day', 'nls_date_language = english')) IN
8 ('Tuesday', 'Sunday')
9 THEN
<snip>
39 /
Trigger created.
SQL>
SQL> INSERT INTO tbl_39_dept_k (dept_no) VALUES (20);
INSERT INTO tbl_39_dept_k (dept_no) VALUES (20)
*
ERROR at line 1:
ORA-20000: you cannot perform DML on Weekend
ORA-06512: at "SCOTT.TGR_WKD_ACTION", line 6
ORA-04088: error during execution of trigger 'SCOTT.TGR_WKD_ACTION'
SQL>
I am pretty new when it comes to SQL and I am currently working on triggers and I have a trigger i am not sure what the problem is. I was wondering if someone could help me figure out what is wrong. Truthfully I am not even sure if this is a good trigger or not. I am having a little trouble with them. Thank you. I appreciate it.
Trigger to raise error on new purchase or updated purchase
CREATE OR REPLACE TRIGGER reminder1
AFTER INSERT OR UPDATE ON PurchasedDeal
FOR EACH ROW
BEGIN
RAISE_APPLICATION_ERROR( 'Notify new Purchased Deal Created or updated' );
END;
All it is saying is this:
Warning: Trigger created with compilation errors.
Not sure which software you are using for developing your PL/SQL code. However, you should find out how to make the "compilation error" messages visible eg
using sqlcl (command line tool)
-- just a test table ...
create table purchaseddeal ( id )
as
select 1 from dual ;
CREATE OR REPLACE TRIGGER reminder1
AFTER INSERT OR UPDATE ON PurchasedDeal
FOR EACH ROW
BEGIN
RAISE_APPLICATION_ERROR( 'Notify new Purchased Deal Created or updated' );
END;
/
SQL> show error
Errors for TRIGGER ...REMINDER1:
LINE/COL ERROR
-------- --------------------------------------------------------------------------------------------
2/1 PL/SQL: Statement ignored
2/1 PLS-00306: wrong number or types of arguments in call to 'RAISE_APPLICATION_ERROR'
When using https://livesql.oracle.com you'll get
-- this will be displayed straightaway after compiling ...
Errors: TRIGGER REMINDER1
Line/Col: 2/1 PL/SQL: Statement ignored
Line/Col: 2/1 PLS-00306: wrong number or types of arguments in call to 'RAISE_APPLICATION_ERROR'
Then, you can find out more by looking at the documentation.
RAISE_APPLICATION_ERROR Procedure
You can invoke the RAISE_APPLICATION_ERROR procedure (defined in the
DBMS_STANDARD package) only from a stored subprogram or method.
Typically, you invoke this procedure to raise a user-defined exception
and return its error code and error message to the invoker.
To invoke RAISE_APPLICATION_ERROR, use this syntax:
RAISE_APPLICATION_ERROR (error_code, message[, {TRUE | FALSE}]); You
must have assigned error_code to the user-defined exception with the
EXCEPTION_INIT pragma. The syntax is:
PRAGMA EXCEPTION_INIT (exception_name, error_code) The error_code is
an integer in the range -20000..-20999 and the message is a character
string of at most 2048 bytes.
It is problably not obvious (to yourself or other programmers) why you would use a procedure called RAISE_APPLICATION_ERROR when things go to plan ie when a row was successfully INSERTed or UPDATED. Maybe the following example is a better illustration of what you wanted to code (or see):
Table: purchaseddeal
SQL> select * from purchaseddeal ;
PRODUCT_ID QTY PRICE
---------- ---------- ----------
1 10 100
Trigger
-- fires when a price is too high or too low
-- (this could also be coded as a CHECK constraint - but the question is about triggers ...).
create or replace trigger checktheprice
before insert or update on purchaseddeal
for each row
begin
if :new.price < 0 then
raise_application_error( -20000, 'Price too low' ) ;
elsif :new.price > 1000 then
raise_application_error( -20001, 'Price too high' ) ;
end if;
end ;
/
Testing
SQL> insert into purchaseddeal values ( 2, 20, 2000 ) ;
Error starting at line : 1 in command -
insert into purchaseddeal values ( 2, 20, 2000 )
Error report -
ORA-20001: Price too high
ORA-06512: at "...CHECKTHEPRICE", line 5
ORA-04088: error during execution of trigger '...CHECKTHEPRICE'
SQL> insert into purchaseddeal values ( 2, 20, -2000 ) ;
Error starting at line : 1 in command -
insert into purchaseddeal values ( 2, 20, -2000 )
Error report -
ORA-20000: Price too low
ORA-06512: at "...CHECKTHEPRICE", line 3
ORA-04088: error during execution of trigger '...CHECKTHEPRICE'
The table is still untouched ...
select * from purchaseddeal ;
SQL> select * from purchaseddeal ;
PRODUCT_ID QTY PRICE
---------- ---------- ----------
1 10 100
Anonymous block and PRAGMA EXCEPTION_INIT
declare
price_too_low exception ;
price_too_high exception ;
-- assign the error_codes to the user-defined exceptions
pragma exception_init( price_too_low, -20000 ) ;
pragma exception_init( price_too_high, -20001 ) ;
begin
insert into purchaseddeal values ( 2, 20, 2000 ) ;
-- insert into purchaseddeal values ( 2, 20, -2000 ) ;
exception
when price_too_low then
dbms_output.put_line( to_char( sqlerrm( -20000 ) ) ) ;
when price_too_high then
dbms_output.put_line( to_char( sqlerrm( -20001 ) ) ) ;
end ;
/
-- output
ORA-20001: Price too high
ORA-06512: at "...CHECKTHEPRICE", line 5
ORA-04088: error during execution of trigger '...CHECKTHEPRICE'
PL/SQL procedure successfully completed.
Some more testing: values in allowed range
-- insert some rows that contain values in the allowed range
insert into purchaseddeal ( product_id, qty, price )
select
level + 1, ( level + 1 ) * 10, ( level + 1 ) * 100.00
from dual
connect by level <= 8 ;
The table now contains ...
SQL> select * from purchaseddeal ;
PRODUCT_ID QTY PRICE
---------- ---------- ----------
1 10 100
2 20 200
3 30 300
4 40 400
5 50 500
6 60 600
7 70 700
8 80 800
9 90 900
9 rows selected.
How I can return two columns into a function?
For example: "EmployeeName | salary" and the values are "Jonas Daniel | $2500$
Using ref cursor is one option:
SQL> create or replace function f_test (par_empno in number)
2 return sys_refcursor
3 is
4 rc sys_refcursor;
5 begin
6 open rc for select ename, sal from emp
7 where empno = par_empno;
8 return rc;
9 end;
10 /
Function created.
SQL> select f_test(7839) from dual;
F_TEST(7839)
--------------------
CURSOR STATEMENT : 1
CURSOR STATEMENT : 1
ENAME SAL
---------- ----------
KING 10000
SQL>
Or, you could try this approach:
SQL> create or replace type t_test_row is object
2 (ename varchar2(20),
3 sal number);
4 /
Type created.
SQL> create or replace type t_test_tab is table of t_test_row;
2 /
Type created.
SQL> create or replace function f_test (par_empno in number)
2 return t_test_tab
3 is
4 l_tab t_test_tab := t_test_tab();
5 begin
6 select t_test_row(ename, sal)
7 bulk collect into l_tab
8 from emp
9 where empno = par_empno;
10
11 return l_tab;
12 end;
13 /
Function created.
SQL> select f_test(7839) from dual;
F_TEST(7839)(ENAME, SAL)
--------------------------------------------------------------------------------
T_TEST_TAB(T_TEST_ROW('KING', 10000))
SQL> -- Or, a nice presentation
SQL> select * from table(f_test(7839));
ENAME SAL
-------------------- ----------
KING 10000
SQL>
Or, you could create a procedure:
SQL> set serveroutput on
SQL> create or replace procedure p_test (par_empno in number,
2 par_ename out varchar2,
3 par_sal out number)
4 is
5 begin
6 select ename, sal
7 into par_ename, par_sal
8 from emp
9 where empno = par_empno;
10 end;
11 /
Procedure created.
SQL> declare
2 l_ename varchar2(20);
3 l_sal number;
4 begin
5 p_test(7839, l_ename, l_sal);
6 dbms_output.put_line('Name = ' || l_ename ||', salary = ' || l_sal);
7 end;
8 /
Name = KING, salary = 10000
PL/SQL procedure successfully completed.
SQL>
But, if you meant to return two scalar values, you might be out of luck.
I want a stored procedure to create a temptable based on 2 columns of table_A, and then check if there are rows in table_B (with 5 columns) that have these 2 columns like the way they are in table_A. Don't do anything to them a delete rows that are not duplicate.
Something like this:
Create Procedure DeleteExtra
as
Create Table #TempTotalHoney
(
HarvestDate Date,
HoneyType VarChar(50)
)
INSERT INTO #TempTotalHoney
Select HarvestDate, HoneyType
From tHoneyHarvest
Group BY HarvestDate, HoneyType
//until here temptable created as I want, but I don't know how to check
//not duplicated rows, I tried this But it is wrong...
Delete From tHoneyWeight
Where HarvestDate AND HoneyType Not in (select HarvestDate, HoneyType
From #TempTotalHoney)
//must check these tow columns together not separately
If(OBJECT_ID('tempdb..#TempTotalHoney') Is Not Null)
Begin
Drop Table #TempTotalHoney
End
This is the error I get:
Msg 4145, Level 15, State 1, Procedure DeleteExtra, Line 17
An expression of non-boolean type specified in a context where a condition is expected, near 'AND'.
Update:
this is #TempTotalHoney that created from table_A
HarvestDate HoneyType
---------------------------------------------------
2017-01-10 Pure
2017-01-10 Semi-Pure
2017-02-03 Pure
2017-02-04 artificial
and
table_B:
RecID HarvestDate HoneyType TotalCombs TotalWeight
----------------------------------------------------------------
1 2017-01-10 Pure 10 22
3 2017-01-10 Semi-Pure 11 24
4 2017-02-03 Pure 22 50
6 2017-02-04 artificial 25 56
8 2017-01-10 Semi-Art 10 18.5
9 2017-02-05 Pure 11 19
I want the RecID 8 and 9 that combination of HarvestDate And HoneyType of them not exists in #TempTotalHoney be deleted.
You can try using below query
DELETE table_B
FROM table_B B
LEFT JOIN #TempTotalHoney A
ON B.HarvestDate = A.HarvestDate
AND B.HoneyType = A.HoneyType
WHERE A.HoneyType is Null;
Hope this would help you out.
I have a table in oracle of which all rows of a column has to be updated with a starting value of 500 and incrementing by 1.
I tried to find something similar online but wasn't able to get anything useful. oracle and PL/SQL is not my expertise. any help would be appreciated.
I won't use PL/SQL since it could be done in plain SQL.
You could use a SEQUENCE starting with 500 and incremented by 1.
For example,
set up
SQL> DROP SEQUENCE s ;
Sequence dropped.
SQL>
SQL> CREATE SEQUENCE s START WITH 500 INCREMENT BY 1;
Sequence created.
SQL>
SQL> DROP TABLE t PURGE;
Table dropped.
SQL>
SQL> CREATE TABLE t AS SELECT LEVEL id FROM dual CONNECT BY LEVEL < =20;
Table created.
SQL>
SQL> SELECT * FROM t;
ID
----------
1
2
3
4
5
6
7
8
9
10
11
ID
----------
12
13
14
15
16
17
18
19
20
20 rows selected.
SQL>
Now, let's update the table with the sequence.
SQL> UPDATE t SET ID = s.nextval;
20 rows updated.
SQL>
SQL> SELECT * FROM t;
ID
----------
500
501
502
503
504
505
506
507
508
509
510
ID
----------
511
512
513
514
515
516
517
518
519
20 rows selected.
SQL>
So, you have all the rows updated with the sequence starting with 500 and incremented by 1.
Please try like this,
DECLARE
VAL = 500;
BEGIN
FOR REC IN ( SELECT
*
FROM
Table1
)
LOOP
UPDATE Table1 SET col1 = VAL WHERE COL1 = REC.COL1 ;
VAL = VAL +1;
END LOOP;
END;
DECLARE
VAL NUMBER := 1;
BEGIN
FOR REC IN ( select *
from customers
)
LOOP
UPDATE customers SET ID1 = VAL WHERE ID = REC.ID ;
VAL := VAL +1;
END LOOP;
END;