Value Set in Oracle Apps using Union - oracle

I need to create a value set which selects items from a custom table for certain run no and union it with Select 'ALL' from dual so that when the user selects ALL the program runs for all the items.
I tried creating a view of the custom table and then used
select item from xx_cust_view where run_no=:$FLEX$.RUN_NO_VS union select 'ALL' from dual
It is saved without error in value set but gives an error when I try to pass values while running the program.
Please suggest.

I don't know Oracle Apps. but I thought that the following example might give you an idea.
It is ran in SQL*Plus, based on HR's departments table. Parameter PAR_DNAME accepts either real department name (such as "Purchasing") or ALL (which is then supposed to return all departments). ROWNUM is here just to restrict number of returned rows (so that I wouldn't display all 27 departments).
Have a look:
SQL> select * from departments
2 where department_name =
3 case when '&&par_dname' = 'ALL' then department_name
4 else '&&par_dname'
5 end
6 --
7 and rownum <= 5;
Enter value for par_dname: Purchasing
DEPARTMENT_ID DEPARTMENT_NAME MANAGER_ID LOCATION_ID
------------- ------------------------------ ---------- -----------
30 Purchasing 114 1700
SQL> undefine par_dname
SQL> /
Enter value for par_dname: ALL
DEPARTMENT_ID DEPARTMENT_NAME MANAGER_ID LOCATION_ID
------------- ------------------------------ ---------- -----------
10 Administration 200 1700
20 Marketing 201 1800
30 Purchasing 114 1700
40 Human Resources 203 2400
50 Shipping 121 1500
SQL>

Value set does not allow union, group by .
So i created a view of the union query and used this view in the value set to fetch the values.

Related

PL/SQL insert record using max function

Create a PL/SQL block to insert a new record into the Department table. Fetch the maximum department id from the Department table and add 10 to it; take this value for department id; 'TESTING' is the value for department name and CHN-102 is the value for Location ID.
Note: Use '/' to terminate your query before compilation and evaluation
Table name : Department
Column name | Data type | Constraints
DEPARTMENT_ID | NUMBER(5) | PK
DEPARTMENT_NAME | VARCHAR2(25) | NOT NULL
LOCATION_ID | VARCHAR2(15)
Sample Output:
DEPARTMENT_ID DEPARTMENT_NAME LOCATION_ID
------------- --------------- -----------
XXXX TESTING CHN-102
The way you described it, it would look like this:
SQL> declare
2 l_department_id department.department_id%type;
3 l_department_name department.department_name%type := 'TESTING';
4 l_location_id department.location_id%type := 'CHN-102';
5 begin
6 select nvl(max(department_id), 10)
7 into l_department_id
8 from department;
9
10 insert into department (department_id, department_name, location_id)
11 values (l_department_id + 10, l_department_name, l_location_id);
12 end;
13 /
PL/SQL procedure successfully completed.
SQL> select * From department;
DEPARTMENT_ID DEPARTMENT_NAME LOCATION_I
------------- -------------------- ----------
20 TESTING CHN-102
SQL>
Note, though, that MAX + 10 is a wrong approach. If two (or more) users run the same procedure at the same time, only the first one who commits changes will be able to do that; other user(s) will violate the primary key constraint because that department_id already exists (as it was inserted moments ago by someone else). Use a sequence instead.

Okay so I am trying to a rownum into a variable but I need it to give me only one value, so 2 if it's the second number in the row

select rownum into v_rownum
from waitlist
where p_callnum=callnum
order by sysdate;
tried doing this but gives too many values.
and if I do p_snum=snum, it will keep returning 1. I need it to return 2 if it's #2 on the waitlist.
select rn into v_rownum
from (select callnum,
row_number() over (order by sysdate) rn
from waitlist)
where p_snum=snum;
Almost got it to work. Running into issues in the first select. I believe I might have to use v_count instead. Also Ordering by Sysdate even if a second apart will order it correctly.
SNU CALLNUM TIME
--- ---------- ---------
101 10125 11-DEC-18
103 10125 11-DEC-18
BTW time is = date which I entered people into waitlist using sysdate. So I suppose ordering by time could work.
create table waitlist(
snum varchar2(3),
callnum number(8),
time date,
constraint fk_waitlist_snum foreign key(snum) references students(snum),
constraint fk_waitlist_callnum foreign key(callnum) references schclasses(callnum),
primary key(snum,callnum)
);
is the waitlist table.
I used Scott's DEPT table to create your WAITLIST; department numbers represent CALLNUM column:
SQL> select * From waitlist;
CALLNUM WAITER
---------- --------------------
10 ACCOUNTING
20 RESEARCH
30 SALES
40 OPERATIONS
How to fetch data you need?
using analytic function (ROW_NUMBER) which orders values by CALLNUMs, you'll know the order
that query will be used as an inline view for the main query that returns number in the waitlist for any CALLNUM
Here's how:
SQL> select rn
2 from (select callnum,
3 row_number() over (order by callnum) rn
4 from waitlist
5 )
6 where callnum = 30;
RN
----------
3
SQL>
rownum in oracle is a generated column, it does not refer to any specific row, it is just the nth row in a set.
With a select into it can only return one row (hence the two many rows error) so rownum will always be 1.
Without more details about your table structure, and how you are uniquely identifying records it is hard to give assist you further with a solution.

How to create a unique id for an existing table in PL SQL?

The situation is that, when I import a file into the database, one of the first thing I usually do is to assign an unique ID for each record.
I normally do below in TSQL
ALTER TABLE MyTable
ADD ID INT IDENTITY(1,1)
I am wondering if there is something similar in PL SQL?
All my search result come back with multiple steps.
Then I'd like to know what PL SQL programmer typically do to ID records after importing a file. Do they do that?
The main purpose for me to ID these records is to trace it back after manipulation/copying.
Again, I understand there is solution there, my further question is whether PL SQL programmer actually do that, or there is other alternative which making this step not necessary in PL SQL?
OK then, as you're on Oracle 11g, there's no identity column there so - back to multiple steps. Here's an example:
I'm creating a table that simulates your imported table:
SQL> create table tab_import as
2 select ename, job, sal
3 from emp
4 where deptno = 10;
Table created.
Add the ID column:
SQL> alter table tab_import add id number;
Table altered.
Create a sequence which will be used to populate the ID column:
SQL> create sequence seq_imp;
Sequence created.
Update current rows:
SQL> update tab_import set
2 id = seq_imp.nextval;
3 rows updated.
Create a trigger which will take care about future inserts (if any):
SQL> create or replace trigger trg_bi_imp
2 before insert on tab_import
3 for each row
4 begin
5 :new.id := seq_imp.nextval;
6 end;
7 /
Trigger created.
Check what's in the table at the moment:
SQL> select * from tab_import;
ENAME JOB SAL ID
---------- --------- ---------- ----------
CLARK MANAGER 2450 1
KING PRESIDENT 5000 2
MILLER CLERK 1300 3
Let's import some more rows:
SQL> insert into tab_import (ename, job, sal)
2 select ename, job, sal
3 from emp
4 where deptno = 20;
3 rows created.
The trigger had silently populated the ID column:
SQL> select * From tab_import;
ENAME JOB SAL ID
---------- --------- ---------- ----------
CLARK MANAGER 2450 1
KING PRESIDENT 5000 2
MILLER CLERK 1300 3
SMITH CLERK 800 4
JONES MANAGER 2975 5
FORD ANALYST 3000 6
6 rows selected.
SQL>
Shortly: you need to
alter table and add the ID column
create a sequence
create a trigger
The end.
The answer given by #Littlefoot would be my recommendation too - but still I thought I could mention the following variant which will work only if you do not intend to add more rows to the table later.
ALTER TABLE MyTable add id number(38,0);
update MyTable set id = rownum;
commit;
My test:
SQL> create table tst as select * from all_tables;
Table created.
SQL> alter table tst add id number(38,0);
Table altered.
SQL> update tst set id = rownum;
3815 rows updated.
SQL> alter table tst add constraint tstPk primary key (id);
Table altered.
SQL>
SQL> select id from tst where id < 15;
ID
----------
1
2
3
4
5
6
7
8
9
10
11
ID
----------
12
13
14
14 rows selected.
But as mentioned initially,- this only fixes numbering for the rows you have at the time of the update - your'e not going to get new id values for new rows anytime later - if you need that, go for the sequence solution.
You can add an id column to a table with a single statement (Oracle 11g, see dbfiddle):
alter table test_
add id raw( 16 ) default sys_guid() ;
Example:
-- create a table without an id column
create table test_ ( str )
as
select dbms_random.string( 'x', 16 )
from dual
connect by level <= 10 ;
select * from test_ ;
STR
ULWL9EXFG6CIO72Z
QOM0W1R9IJ2ZD3DW
YQWAP4HZNQ57C2UH
EETF2AXD4ZKNIBBF
W9SECJYDER793MQW
alter table test_
add id raw( 16 ) default sys_guid() ;
select * from test_ ;
STR ID
ULWL9EXFG6CIO72Z 0x782C6EBCAE2D7B9FE050A00A02005D65
QOM0W1R9IJ2ZD3DW 0x782C6EBCAE2E7B9FE050A00A02005D65
YQWAP4HZNQ57C2UH 0x782C6EBCAE2F7B9FE050A00A02005D65
EETF2AXD4ZKNIBBF 0x782C6EBCAE307B9FE050A00A02005D65
W9SECJYDER793MQW 0x782C6EBCAE317B9FE050A00A02005D65
Testing
-- Are the id values unique and not null? Yes.
alter table test_
add constraint pkey_test_ primary key ( id ) ;
-- When we insert more rows, will the id be generated? Yes.
begin
for i in 1 .. 100
loop
insert into test_ (str) values ( 'str' || to_char( i ) ) ;
end loop ;
end ;
/
select * from test_ order by id desc ;
-- last 10 rows of the result
STR ID
str100 0x782C806E16A5E998E050A00A02005D81
str99 0x782C806E16A4E998E050A00A02005D81
str98 0x782C806E16A3E998E050A00A02005D81
str97 0x782C806E16A2E998E050A00A02005D81
str96 0x782C806E16A1E998E050A00A02005D81
str95 0x782C806E16A0E998E050A00A02005D81
str94 0x782C806E169FE998E050A00A02005D81
str93 0x782C806E169EE998E050A00A02005D81
str92 0x782C806E169DE998E050A00A02005D81
str91 0x782C806E169CE998E050A00A02005D81
Regarding your other questions:
{1} Then I'd like to know what PL SQL programmer typically do to ID records after importing a file. Do they do that? The main purpose for me to ID these records is to trace it back after manipulation/copying.
-> As you know, the purpose of an id is: to identify a row. We don't "do anything to IDs". Thus, your usage of IDs seems legit.
{2} Again, I understand there is solution there, my further question is whether PL SQL programmer actually do that, or there is other alternative which making this step not necessary in PL SQL?
-> Not quite sure what you are asking here. Although there is a ROWID() pseudocolumn (see documentation), we should not use it to identify rows.
"You should not use ROWID as the primary key of a table. If you delete
and reinsert a row with the Import and Export utilities, for example,
then its rowid may change. If you delete a row, then Oracle may
reassign its rowid to a new row inserted later."

How to assign a value to variable from select statement (PL/SQL Developer)

I'm working with PL/SQL Developer.
I'm trying to update values in a column(existing table).
The values used to populate rows should be auto incremented. The starting value is the maximum value that already exist in such field.
An example, I have the following table
ORDER_ID T_NAME T_PRICE
20 CAR 50
NULL VAN 100
NULL BIKE 10
NULL BOAT 300
After running the query I would expect the table to look like:
ORDER_ID T_NAME T_PRICE
20 CAR 50
21 VAN 100
22 BIKE 10
23 BOAT 300
The query I created so far is:
DECLARE
temp_order_id number;
BEGIN
:temp_order_id = SELECT ISNULL(MAX((ORDER_ID)),0) + 1 FROM SALES_ACC;
update SALES_ACC
set (ORDER_ID) = :temp_order_id , :temp_order_id = :temp_order_id + 1
where (ORDER_ID) is null;
END;
Oracle doesn't like assigning a value from select statement to the temp_order_id variable.
Does anyone has any idea how to fix it?
You don't need pl/sql for this - you can do it in a single update statement - eg:
create table test1 as
select 20 order_id, 'CAR' t_name, 50 t_price from dual union all
select null order_id, 'VAN' t_name, 100 t_price from dual union all
select null order_id, 'BIKE' t_name, 10 t_price from dual union all
select null order_id, 'BOAT' t_name, 300 t_price from dual;
update test1
set order_id = (select max(order_id) from test1) + rownum
where order_id is null;
commit;
select * from test1
order by 1;
ORDER_ID T_NAME T_PRICE
---------- ------ ----------
20 CAR 50
21 VAN 100
22 BIKE 10
23 BOAT 300
drop table test1;
As a side note, it sounds like order_id is something that should really be the primary key of the table - if you had that, then you wouldn't be allowed to add a row without a value. Plus, you would also need a sequence that you would then use when inserting data into the table - e.g.:
insert into test1 (order_id, t_name, t_price)
values (test1_seq.nextval, 'TRIKE', 30);
ORACLE's recomended way for this is either:
Create a sequence and a trigger on the table to assign order_id as soon as row is being inserted
or, for Oracle 12c, you can have an IDENTITY column
See How to create id with AUTO_INCREMENT on Oracle?, both approaches are described there.
Within the DECLARE ... BEGIN ... END; section you are in PL/SQL syntax. That is not equal to the SQL syntax. Within PL/SQL syntax you should make use of the so called select into statement.
SELECT ISNULL(MAX((ORDER_ID)),0) + 1
into :temp_order_id
FROM SALES_ACC

the number of same record until this row

Is it possible to retrieve current number of same record for each row by using oracle pl/sql?
For example,
I have class table which consists of id, name, age columns
I want to have the sequence of student with the same name and age entering the class, assuming that id is countering up without altering data structure.
Thanks.
Regards,
Jim
Not sure I entirely get what you're asking for; you have an odd turn of phrase. An example of input data and expected result is always useful.
Perhaps something like this:
select id, name, age
from your_table
where (name, age) in
( select name. age
from your_table
group by name, age
having count(id) > 1 )
order by name, age, id
/
You could solve this with analytics. However, you still need an outer query to filter out the records which aren't duplicated, so I'm not sure what you'd gain:
select * from (
select id, name, age
, count(id) over (partition by name, age) as dup_count
from your_table )
where dup_count > 1
order by name, age, id
/
I'm not sure either, but it sounds to me something related to analytic functions. Take this as an example, look at srlno column, calculated using analytic functions:
SELECT empno, deptno, hiredate,
ROW_NUMBER( ) OVER (PARTITION BY
deptno ORDER BY hiredate
NULLS LAST) SRLNO
FROM emp
WHERE deptno IN (10, 20)
ORDER BY deptno, SRLNO;
EMPNO DEPTNO HIREDATE SRLNO
------ ------- --------- ----------
7782 10 09-JUN-81 1
7839 10 17-NOV-81 2
7934 10 23-JAN-82 3
7369 20 17-DEC-80 1
7566 20 02-APR-81 2
7902 20 03-DEC-81 3
7788 20 09-DEC-82 4
7876 20 12-JAN-83 5
More on analyltic functions:
http://www.orafaq.com/node/55
Remember, is a better approach if you can achieve your goal with a SQL instead of PL/SQL.

Resources