Change condition in where clause based on a boolean (Oracle) - sql

CREATE OR REPLACE TRIGGER "EVGENIJ_BOBROVICH"."FIX_UPD_LIMITS"
BEFORE UPDATE OR DELETE ON "EVGENIJ_BOBROVICH"."MAP_CALCULATION_SHOP_LIMITS"
FOR EACH ROW
DECLARE
is_deleted_dependant VARCHAR2(1 BYTE);
is_editable_dependant VARCHAR2(1 BYTE);
OPERATION BOOLEAN := UPDATING OR DELETING;
BEGIN
SELECT IS_DELETE, IS_EDITABLE INTO is_deleted_dependant, is_editable_dependant
FROM MAP_CALCULATION MC INNER JOIN map_calculation_group MG ON MC.ID_CALC = MG.ID_CALC
WHERE MG.ID_CALC = MC.ID_CALC AND MG.ID_GROUP =
(CASE WHEN UPDATING THEN :new.id_group WHEN DELETING THEN :old.id_group)
...
END;
/
How to change these checks in the where clause based on the updating and deleting flags?

No, it won't work. A simple example:
SQL> create table test as select * From dept;
Table created.
SQL> create or replace trigger trg_test
2 before update or delete on test
3 for each row
4 declare
5 l_cnt number;
6 begin
7 select count(*) into l_cnt
8 from emp where deptno = case when updating then :new.deptno
9 when deleting then :old.deptno
10 end;
11 end;
12 /
Warning: Trigger created with compilation errors.
SQL> show err
Errors for TRIGGER TRG_TEST:
LINE/COL ERROR
-------- -----------------------------------------------------------------
4/3 PL/SQL: SQL Statement ignored
5/46 PL/SQL: ORA-00920: invalid relational operator
SQL>
Error is here:
8 from emp where deptno = case when updating then :new.deptno
^^^^
Which means that you'll have to do something like this:
SQL> create or replace trigger trg_test
2 before update or delete on test
3 for each row
4 declare
5 l_deptno test.deptno%type;
6 l_cnt number;
7 begin
8 if updating then
9 l_deptno := :new.deptno;
10 elsif deleting then
11 l_deptno := :old.deptno;
12 end if;
13
14 select count(*) into l_cnt
15 from emp where deptno = l_deptno;
16 end;
17 /
Trigger created.
SQL>

Related

Can we use %rowtype attribute inside the plsql record?

Can we use %rowtype attribute inside the plsql record like the below code..
type xx is RECORD
( v_emp employees%rowtype ,
v_loc departments.LOCATION_ID%type
);
v_data xx;
I can, and I hope you can too.
SQL> set serveroutput on
SQL>
SQL> declare
2 type xx is RECORD
3 ( v_emp emp%rowtype ,
4 v_loc dept.LOC%type );
5 v_data xx;
6 begin
7 v_data.v_emp.ename := 'LF';
8 v_data.v_loc := 'x';
9
10 dbms_output.put_line(v_data.v_emp.ename ||', '|| v_data.v_loc);
11 end;
12 /
LF, x
PL/SQL procedure successfully completed.
SQL>

pl-sql errror on select HR schema

i want to do something like that.. but in a function.. select * from employees where employee_id = &employee_id in HR schema of oracle
Q: Create Function “SEARCH_EMPLOYEE” that receives an Employee ID and returns all its attributes through an output parameter with a data structure that represents all its information
R:
Create or replace FUNCTION get_complete_employee (&in_employee_id IN NUMBER)
AS person_details;
BEGIN
SELECT * --'Name-'||first_name||' '|| last_name
into person_details
FROM employees;
Dbms_output.put_line(person_details);
-- END get_complete_employee;
end;
i have a error of sintax i guess..
i don't know what is wrong
If you are learning how to create the function which returns entire row of the table then following is the basic example of doing the same:
Table data:
SQL> select * from EMP;
EMP_ID EMP_NAME E
---------- -------------------- -
10 John N
20 May Y
SQL>
Function:
SQL> CREATE OR REPLACE FUNCTION GET_COMPLETE_EMPLOYEE (
2 IN_EMPLOYEE_ID IN NUMBER
3 ) RETURN EMP%ROWTYPE AS
4 MY_ROWTYPE EMP%ROWTYPE;
5 BEGIN
6 SELECT
7 * --'Name-'||first_name||' '|| last_name
8 INTO MY_ROWTYPE
9 FROM
10 EMP
11 WHERE
12 EMP_ID = IN_EMPLOYEE_ID;
13
14 RETURN MY_ROWTYPE;
15 END;
16 /
Function created.
SQL>
Calling the function and result:
SQL> SET SERVEROUT ON
SQL>
SQL> DECLARE
2 EMPTYPE EMP%ROWTYPE;
3 BEGIN
4 EMPTYPE := GET_COMPLETE_EMPLOYEE(10);
5 DBMS_OUTPUT.PUT_LINE(EMPTYPE.EMP_NAME);
6 END;
7 /
John
You must have to handle multiple exception scenarios in real-world coding.
Cheers!!

Converting column data into row in pl/sql

Hi When i went for an interview they asked me this question.
Create table course(Name CHAR(10));
insert into course values ('Java');
insert into course values ('Oracle');
insert into course values ('Python');
insert into course values ('C');
insert into course values ('C++');
o/p:
Java Oracle python c c++
Thanks in advance,
Sandhya.
I presume that NAME column's datatype should have been VARCHAR2, not CHAR.
Anyway, another option (similar to Tejash's LISTAGG) which uses XMLAGG and is safer if the result is larger than 4000 characters.
SQL> SELECT RTRIM (
2 XMLAGG (XMLELEMENT (e, name || ' ') ORDER BY null).EXTRACT (
3 '//text()'),
4 ',')
5 result
6 FROM course;
RESULT
------------------------------------------------------------
Java Oracle Python C C++
SQL>
Or, as you tagged the question with PL/SQL tag, then an anonymous PL/SQL block might look like this:
SQL> set serveroutput on
SQL>
SQL> declare
2 l_result varchar2(100);
3 begin
4 for cur_r in (select name from course) loop
5 l_result := l_result ||' '|| cur_r.name;
6 end loop;
7
8 dbms_output.put_line(trim(l_result));
9 end;
10 /
Java Oracle Python C C++
PL/SQL procedure successfully completed.
SQL>
Or - similarly - a function:
SQL> create or replace function f_course
2 return varchar2
3 is
4 l_result varchar2(100);
5 begin
6 for cur_r in (select name from course) loop
7 l_result := l_result ||' '|| cur_r.name;
8 end loop;
9
10 return trim(l_result);
11 end;
12 /
Function created.
SQL> select f_course from dual;
F_COURSE
--------------------------------------------------------------
Java Oracle Python C C++
SQL>
Or, a procedure with an OUT parameter:
SQL> create or replace procedure p_course (par_result out varchar2)
2 is
3 l_result varchar2(100);
4 begin
5 for cur_r in (select name from course) loop
6 l_result := l_result ||' '|| cur_r.name;
7 end loop;
8
9 par_result := trim(l_result);
10 end;
11 /
Procedure created.
SQL> declare
2 l_out varchar2(100);
3 begin
4 p_course(l_out);
5 dbms_output.put_line(l_out);
6 end;
7 /
Java Oracle Python C C++
PL/SQL procedure successfully completed.
SQL>
As you can see, quite a few options; use the one that most suits your needs.
You can use an aggregate function - LISTAGG as following:
SQL> SELECT
2 LISTAGG(TRIM(NAME), ' ') WITHIN GROUP(
3 ORDER BY
4 NULL
5 ) AS RESULT
6 FROM
7 COURSE;
RESULT
--------------------------------------------------------------------------------
C C++ Java Oracle Python
SQL>
Cheers!!

How to execute DDLs conditionally in oracle?

I have a script that creates a lot of tables, indexes, triggers etc. And I want to run all those DDLs conditionally. i tried to wrap the script with 'if then' but it didn't work
IF exists (select 1 from xxx where yyy) THEN
create table...
create table...
CREATE UNIQUE INDEX ...
CREATE TRIGGER ...
END IF;
how can i achieve that?
One of the ways:
begin
for cur in (select 1 from xxx where yyy and rownum <= 1) loop
execute immediate 'create table...';
execute immediate 'create table...';
execute immediate 'create unique index...';
end loop;
end;
/
P.S. One more way is to generate exception and proceed in SQL*Plus.
file example.sql:
SET ECHO OFF
SET VERIFY OFF
WHENEVER SQLERROR EXIT;
VAR x NUMBER
EXEC :x := &1
BEGIN
FOR cur IN (SELECT 1 FROM dual WHERE 1=:x) LOOP
RETURN;
END LOOP;
RAISE NO_DATA_FOUND;
END;
/
PROMPT Here we are
Result:
SQL> #example
Enter value for 1 1: 1
PL/SQL procedure completed.
PL/SQL procedure completed.
Here we are
SQL> #example
Enter value for 1: 2
PL/SQL procedure completed.
BEGIN
*
error in line 1:
ORA-01403: no data found
ORA-06512: in line 5
When I use value 2 the block raises exception and the script exists SQL*Plus.
P.S. One more example in response - hope this cleas questions below. I create table only when it does not exist. Table containts 1024 partitions and ' characters in DEFAULT statement. Text size > 32K.
SQL> set serveroutput on
SQL> DECLARE
2 sql_code clob;
3 delim varchar2(1) := '';
4 amount int;
5 sql_text varchar2(32767);
6 BEGIN
7
8 dbms_lob.createtemporary(sql_code,cache => true);
9 sql_text := q'[CREATE TABLE TEST_TAB (X INT PRIMARY KEY, Y VARCHAR2(10) DEFAULT 'DEF', Z INTEGER) PARTITION BY RANGE(Z) ( ]';
10 amount := length(sql_text);
11 dbms_lob.writeappend(sql_code,amount,sql_text);
12
13 for i in 1..1024 loop
14 sql_text := delim||'PARTITION P_'||i||' VALUES LESS THAN ('||i||')';
15 amount := length(sql_text);
16 dbms_lob.writeappend(sql_code,amount,sql_text);
17 delim := ',';
18 end loop;
19
20 dbms_lob.writeappend(sql_code,1,')');
21
22 FOR cur IN (
23 SELECT * FROM dual WHERE NOT EXISTS (
24 SELECT * FROM user_tables WHERE table_name = 'TEST_TAB')
25 ) LOOP
26 EXECUTE IMMEDIATE sql_code;
27 END LOOP;
28
29 dbms_output.put_line(dbms_lob.getlength(lob_loc => sql_code));
30
31 END;
32 /
39877
PL/SQL procedure completed.
SQL> desc test_tab
Имя Пусто? Тип
----------------------------------------- -------- ----------------------------
X NOT NULL NUMBER(38)
Y VARCHAR2(10)
Z NUMBER(38)
SQL> select count(*) from user_tab_partitions where table_name = 'TEST_TAB';
COUNT(*)
----------
1024

If I turn a collection of Number into a table, what's the name of the column? 10gR2

If I wanted to replace the * with a column name, what would it be?
create type mytable$t as table of number;
/
declare
mytmou mytable$t := myTable$T();
cnt pls_integer ;
begin
mytmou := myTable$T(1,2,3,4,5,6);
SELECT count(*) into cnt From Table (mytmou);
dbms_output.put_line(cnt);
end;
6
COLUMN_VALUE is the name of the column
SQL> ed
Wrote file afiedt.buf
1 declare
2 mytmou mytable$t := myTable$T();
3 cnt pls_integer ;
4 begin
5 mytmou := myTable$T(1,2,3,4,5,6);
6 SELECT count(column_value) into cnt From Table (mytmou);
7 dbms_output.put_line(cnt);
8* end;
SQL> /
6
PL/SQL procedure successfully completed.