Oracle 'MEMBER OF' function - oracle11g

I was trying to use MEMBER OF function but receiving error "PLS-00306: wrong number or types
of arguments in call to 'MEMBER OF'.". Please let me know, how i can use 'MEMBER OF' function
correctly, i want to avoid iteration.
Table: Employee
EMP_ID EMP_NAME EMP_BRANCH
1 Oliver 104
2 Harry 105
3 Jack 105
4 Jacob 103
DECLARE
TYPE emp_name_type IS RECORD(emp_name employee.emp_name%type);
TYPE emp_name_table_type IS TABLE OF emp_name_type;
emp_name_table_type_array emp_name_table_type;
BEGIN
select x.emp_name BULK COLLECT
into emp_name_table_type_array
from (
select e.emp_name, min(e.emp_id) as emp_id
from employee e
where e.emp_branch = 105
group by e.emp_name
) x
order by x.emp_id;
-- receiving output Harry + Jack
FOR i IN emp_name_table_type_array.FIRST .. emp_name_table_type_array.LAST LOOP
dbms_output.put_line(emp_name_table_type_array(i).emp_name);
END LOOP;
-- here i want to implement something like bellow using 'Member OF' function
IF 'Harry' MEMBER OF emp_name_table_type_array THEN
dbms_output.put_line('yes');
ELSE
dbms_output.put_line('no');
END IF;
END;
/
Thank you

You have one type declaration too many (and have to fix the first dbms_output.put_line call because of that).
SQL> DECLARE
2 TYPE emp_name_table_type IS TABLE OF employee.emp_name%type;
3 emp_name_table_type_array emp_name_table_type;
4 BEGIN
5 select x.emp_name BULK COLLECT
6 into emp_name_table_type_array
7 from (
8 select e.emp_name, min(e.emp_id) as emp_id
9 from employee e
10 where e.emp_branch = 105
11 group by e.emp_name
12 ) x
13 order by x.emp_id;
14
15 -- receiving output Harry + Jack
16 FOR i IN emp_name_table_type_array.FIRST .. emp_name_table_type_array.LAST LOOP
17 dbms_output.put_line(emp_name_table_type_array(i));
18 END LOOP;
19
20 -- here i want to implement something like bellow using 'Member OF' function
21 IF 'Harry' MEMBER OF emp_name_table_type_array THEN
22 dbms_output.put_line('yes');
23 ELSE
24 dbms_output.put_line('no');
25 END IF;
26 END;
27 /
Harry
Jack
yes
PL/SQL procedure successfully completed.
SQL>

Related

how to resolve Warning: Trigger created with compilation errors

I'm trying to create a trigger where if the total number of customer reaches 10 then it should raise an error
This is my plsql code:
SQL> CREATE OR REPLACE TRIGGER customer_count_check
2 BEFORE INSERT OR UPDATE ON customer2
3 FOR EACH ROW
4 DECLARE
5 count_customer NUMBER(5);
6 BEGIN
7 SELECT COUNT(*) INTO count_customer FROM customer2
8 WHERE cusid = :new.cusid;
9 IF count_customer > 10 THEN
10 Raise_application_error(-20000,'Maximum customer count:' ||
11 count_customer || 'reached');
12 ENDIF;
13 END;
14 /
and this is the warning I'm getting:
Warning: Trigger created with compilation errors.
SQL> SHOW ERROR;
Errors for TRIGGER CUSTOMER_COUNT_CHECK:
LINE/COL ERROR
-------- -----------------------------------------------------------------
10/4 PLS-00103: Encountered the symbol ";" when expecting one of the
following:
if
I sometimes also wish the error messages would be more clear.
In line 12:
Wrong
ENDIF;
Right:
END IF;
Also the line counting is sometimes not so intuitive. It says 10/4 while it seems to be 12/4. But the first 2 lines are not considered part of the triggers code and so the counting is line 10 column 4.
SQL> CREATE OR REPLACE TRIGGER customer_count_check
2 BEFORE INSERT OR UPDATE ON customer2
3 FOR EACH ROW
4 DECLARE
5 count_customer NUMBER(5);
6 BEGIN
7 SELECT COUNT(*) INTO count_customer FROM customer2
8 WHERE cusid = :new.cusid;
9 IF count_customer > 10 THEN
10 Raise_application_error(-20000,'Maximum customer count:' ||
11 count_customer || 'reached');
12 END IF;
13 END;
14 /

"ORA-24344: success with compilation error"

i just started with pl/sql and found this error. can someone tell what the problem is.
create or replace procedure findmin(x in number, y in number, z out
number)
is
begin
if x<y then z:= x;
else z:=y;
end if;
end;
set serveroutput on;
declare
a number;
b number;
c number;
begin
a:=23;
b:=46;
findmin(a, b, c);
dbms_output.put_line('minimum of the 2 numbers is' || c);
end;
There is NO error. Might be you re not executing it correctly.
SQL> CREATE OR REPLACE PROCEDURE findmin(
2 x IN NUMBER,
3 y IN NUMBER,
4 z OUT NUMBER)
5 IS
6 BEGIN
7
8 IF x<y THEN
9 z:= x;
10
11 ELSE
12 z:=y;
13
14 END IF;
15
16 END;
17
18 /
Procedure created.
SQL> set serveroutput on;
SQL> DECLARE
2 a NUMBER;
3 b NUMBER;
4 c NUMBER;
5 BEGIN
6 a:=23;
7 b:=46;
8 findmin(a, b, c);
9 dbms_output.put_line('minimum of the 2 numbers is ' || c);
10
11 END;
12 /
minimum of the 2 numbers is 23
PL/SQL procedure successfully completed.

PL/SQL Return Only 1 Row for Each Grouping

I have table that lists items like below. It basically has Operation Numbers (OP_NO) that tell where a product is at in the process. These OP Numbers can be either Released or Completed. They follow a process as in 10 must happen before 20, 20 must happen before 30 etc. However users do not update all steps in reality so we end up with some items out of order complete while the earlier steps are not as show below (OP30 is completed but OP 10 and 20 are not).
I basically want to produce a listing of each ORDER_ID showing the furthest point of completion for each ORDER_ID. I figured I could do this by querying for STATUS = 'Completed' and Sorting by OP_NO Desc. However I can't figure out how to produce only 1 result for each ORDER_ID. For example in ORDER_ID 345 Steps 10 and 20 are completed. I would only want to return that STEP 20 is where it is currently at. I was figuring I could do this with 'WHERE ROWNUM <= 1' but haven't had much luck. Could any experts weigh in?
Thanks!
ORDER_ID | ORDER_SEC | ORDER_RELEASE | OP_NO | STATUS | Description
123 2 3 10 Released Op10
123 2 3 20 Released Op20
123 2 3 30 Completed Op30
123 2 3 40 Released Op40
345 1 8 10 Completed Op10
345 1 8 20 Completed Op20
345 1 8 30 Released Op30
345 1 8 40 Released Op40
If I understand correctly what you want the below should do what you need. Just replace test table with your table name.
select *
from test_table tst
where status = 'Completed'
and op_no = (select max(op_no)
from test_table tst1
where tst.order_id = tst1.order_id
and status = 'Completed');
Given your sample data this produced the below results.
Order_Id Order_Sec Order_Release op_no Status Description
123 2 3 30 Completed Op30
345 1 8 20 Completed Op20
Cheers
Shaun Peterson

Union and Count Collections in Neo4j

My simple database contains nodes of 'terms' and 'codes' linked to each other.
There are two types of relationships.
Relationships between 'terms' and 'codes' called :CODE and are undirected (or read in both directions equally).
Relationships between 'terms' called :NT (which means narrow term) and are directed.
I want to walk thru all the 'terms' from top to bottom and collect all the unique codes and count them.
This is my query:
MATCH (a)-[:NT*]->(b), (a)-[:CODE]-(c), (b)-[:CODE]-(d)
WHERE a.btqty = 0
RETURN a.termid AS termid, a.maxlen AS maxlen, COUNT(DISTINCT c.code) + COUNT(DISTINCT d.code) AS total, COLLECT(DISTINCT c.code) + COLLECT(DISTINCT d.code) AS codes
ORDER BY termid;
This is what I get:
termid maxlen total codes
22 2 3 ["S70","S43","S70"]
25 4 9 ["S20","S21","S54","S61","S63","S63","S21","S61","S54"]
26 2 9 ["S99","S98","S29","S13","S13","S20","S29","S14","S15"]
68 5 13 ["S38","S11","S12","S11","S12","S38","S37","S21","S36","S22","S98","S63","S58"]
123 2 3 ["S38","S12","S12"]
154 2 2 ["S58","S58"]
155 4 3 ["S63","S62","S63"]
159 2 2 ["S36","S36"]
...
I need to get rid of duplicates in collection and count them properly like this:
termid maxlen total codes
22 2 2 ["S43","S70"]
25 4 5 ["S20","S21","S54","S61","S63"]
26 2 7 ["S99","S98","S29","S13","S20","S14","S15"]
68 5 10 ["S38","S11","S12","S37","S21","S36","S22","S98","S63","S58"]
123 2 2 ["S38","S12"]
154 2 1 ["S58"]
155 4 2 ["S63","S62"]
159 2 1 ["S36"]
...
I think this is something about REDUCE function to apply but I do not know how to use it.
Thank you for your help!
You're right, this can be solved using REDUCE. Inside the reduce you need to check if the current element already exists in the accumulator and conditionally amend it:
MATCH (a)-[:NT*]->(b), (a)-[:CODE]-(c), (b)-[:CODE]-(d)
WHERE a.btqty = 0
WITH a.termid AS termid, a.maxlen AS maxlen,
REDUCE(uniqueCodes=[],
x in COLLECT(DISTINCT c.code) + COLLECT(DISTINCT d.code) |
CASE WHEN x IN uniqueCodes THEN uniqueCodes ELSE uniqueCodes+x END
) AS codes
ORDER BY termid
RETURN termid, maxlen, count(codes) as total, codes

dynamic pivoting

I am hoping to get some help on a view which needs to be pivoted, I am not sure though.
View is in following format:
CASE CASE_ORDER MANAGER MONTHLY_CASES FISCAL_CASES
case_1 1 John 15 84
case_1 1 Jeff 10 80
case_2 2 John 20 90
case_2 2 Jeff 13 65
case_3 3 John 7 72
case_3 3 Jeff 17 70
My final chart should look like the following:
CASE CASE_ORDER JOHN_CURR_MONTH JOHN_FY JOHN_CURR_MONTH JOHN_FY
case_1 1 15 84 10 80
case_2 2 20 90 13 65
case_3 3 7 72 17 70
My problem is that managers can change and so does the number of managers from month to month,
so I can't hard code their names (ie. 'mgr1' and 'mgr2') and use DECODE. It has to be dynamic...
Thanks for your suggestion, I figured it out. In fact there is a similar answer in tom kyte's blog (http://www.oracle.com/technetwork/issue-archive/2012/12-jul/o42asktom-1653097.html) which I modified for my purpose. Here it is:
CREATE OR REPLACE PROCEDURE dynamic_pivot_proc ( p_cursor IN OUT SYS_REFCURSOR )
AS
l_query LONG := 'SELECT case_order, case';
BEGIN
FOR x IN (SELECT DISTINCT manager FROM test_table ORDER BY 1 )
LOOP
l_query := l_query ||
REPLACE( q'|, MAX(DECODE(manager,'$X$',monthly_total)) $X$_current_month|',
'$X$', dbms_assert.simple_sql_name(x.manager) ) ||
REPLACE( q'|, MAX(DECODE(manager,'$X$',fiscal_total)) $X$_fy|',
'$X$', dbms_assert.simple_sql_name(x.manager) );
END LOOP;
l_query := l_query || ' FROM test_table
GROUP BY case_order, case
ORDER BY case_order ';
OPEN p_cursor FOR l_query;
END;
SQL> variable x refcursor;
SQL> exec dynamic_pivot_proc( :x );
SQL> print x
CASE CASE_ORDER JEFF_CURRENT_MONTH JEFF_FY JOHN_CURRENT_MONTH JOHN_FY
1 case_1 10 80 15 84
2 case_2 13 65 20 90
3 case_3 17 70 7 72
Now the thing is instead of printing the result I want to store it in a view. How do I achieve that? I tried to modify the line
l_query LONG := 'SELECT case_order, case';
with
l_query LONG := 'CREATE OR REPLACE VIEW SELECT case_order, case';
Needless to say that it did not work because CREATE OR REPLACE is a DDL statement, so some how I have to use EXECUTE IMMEDIATE.
Any suggestion? Thanks in advance.

Resources