What is the best join condition for this two scenarios - oracle

I have two tables that i am trying to join to come up with the data that i need to report on.
First table contains all the interns that company hired.
Second table contain all the full the people that were interns but have been hired into full time position.
Requirement is to pull data that shows all the hired interns and out of those interns, get a count of all the ones that we hired into full time position.
Problem is when I do inner join I am only getting interns that were hired into full time position and not all the interns that were hired irrespective of whether they transitioned to full time or not.
Any suggestions?

A suggestion is to use outer join (instead of inner join).
Here's an example: sample tables:
SQL> create table t_first
2 (id number,
3 name varchar2(20));
Table created.
SQL> create table t_second
2 (id number,
3 name varchar2(20));
Table created.
SQL> insert into t_first (id, name)
2 select 1, 'Little' from dual union all
3 select 2, 'Foot' from dual union all
4 select 3, 'Scott' from dual union all
5 select 4, 'Tiger' from dual;
4 rows created.
SQL> insert into t_second (id, name)
2 select 3, 'Scott' from dual union all
3 select 4, 'Tiger' from dual;
2 rows created.
Select all of them, distinguish those who were hired to full time position:
SQL> select h.id, h.name,
2 decode(f.id, null, 'No', 'Yes') full_time_position
3 from t_first h left join t_second f on h.id = f.id
4 order by h.id;
ID NAME FUL
---------- -------------------- ---
1 Little No
2 Foot No
3 Scott Yes
4 Tiger Yes
SQL>
I'm not sure what you meant by "counting" those who were hired to full time position. Where would you want to display that information? How? If you could provide an example, it would be easier to suggest a solution.

Related

Problem in merge condition in oracle when merging two tables

I have a table which has data as:
id payor_name
---------------
1 AETNA
2 UMR
3 CIGNA
4 METLIFE
4 AETNAU
5 ktm
6 ktm
Id and payor_name are two columns.So,
My expected output is:
id payor_name
---------------
1 AETNA
2 UMR
3 CIGNA
4 METLIFE
4 AETNAU
6 ktm ...> I want to change the id of this row to be 6 from 5.
6 ktm
I want one to one mapping between id and payor_name.So,this is what I tried:
MERGE INTO offc.payor_collec A
USING (select id from offc.payor_collec where payor_name in(
select payor_name from offc.payor_collec group by payor_name having count(distinct id)>=2)) B
ON (A.id=B.id)
WHEN MATCHED THEN
UPDATE SET A.id=B.id
But when I compiled I got error as:
Error at line 1
ORA-38104: Columns referenced in the ON Clause cannot be updated: "A"."ID"
Id is number where as payor_name is varchar2.
How can I achieve this result?
MERGE works, but slightly different than your code.
SQL> select * from test;
ID PAYOR
---------- -----
1 aetna
2 umr
5 ktm
6 ktm
SQL> merge into test t
2 using (select max(t1.id) id,
3 t1.payor_name
4 from test t1
5 group by t1.payor_name
6 ) x
7 on (x.payor_name = t.payor_name)
8 when matched then update set
9 t.id = x.id;
4 rows merged.
SQL> select * from test;
ID PAYOR
---------- -----
1 aetna
2 umr
6 ktm
6 ktm
SQL>
Use a correlated subquery:
UPDATE PAYOR_COLLEC pc
SET pc.ID = (SELECT MAX(pc2.ID)
FROM PAYOR_COLLEC pc2
WHERE pc2.PAYOR_NAME = pc.PAYOR_NAME)
dbfiddle here
You can use a MERGE statement, as you tried and as Littlefoot has shown.
You can also use a correlated subquery as Bob Jarvis has shown, but that will be quite inefficient.
Many Oracle developers are unaware that you can also update through a join. Worse, there are many who say "there is no such thing in Oracle."
In your problem, you need to join your table to an aggregate query (picking just the max id for each payor_name) and the join is on the group by column in the aggregate. This already guarantees that the join column will be unique in the right-hand table; that is all Oracle needs to allow the update through join.
Here is a complete example, starting with the create table statement, then the update and then showing the table after the update. Note that I don't need any constraints (like primary key, not null, unique, etc.) or indexes on the base table. If they do exist, so much the better, but the solution works in the most general case.
create table t (id, payor_name) as
select 1, 'AETNA' from dual union all
select 2, 'UMR' from dual union all
select 3, 'CIGNA' from dual union all
select 4, 'METLIFE' from dual union all
select 4, 'AETNAU' from dual union all
select 5, 'ktm' from dual union all
select 6, 'ktm' from dual;
Table T created.
update
(
select id, payor_name, max_id
from t inner join
(select max(id) as max_id, payor_name from t group by payor_name)
using (payor_name)
)
set id = max_id where id != max_id
;
1 row updated.
select * from t;
ID PAYOR_NAME
----- ----------
1 AETNA
2 UMR
3 CIGNA
4 METLIFE
4 AETNAU
6 ktm
6 ktm
Notice the where clause at the end of the update statement, too. You don't want to update rows to their pre-existing value; that will still generate undo and redo data (although I understand that Oracle has changed that in more recent versions - it now doesn't generate undo and redo unless a row did indeed change). I assume ID is NOT NULL - otherwise you should rewrite the where clause as
where decode(id, max_id, 0) is null
or equivalent

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.

Oracle update from random on another table

I have some fields in table1 to update with random values from some fields in table2.
I have to random into rows of table2 and update each rows of table1 with the same rows values of table2.
Here is my SQL code, but it doesn't work.
update owner.table1 t1
set (t1.adress1, t1.zip_code, t1.town) = (select t2.adress, t2.zip_code, t2.town
from table1 t2
where id = trunc(dbms_random.value(1,20000)))
Result: all rows are updated with the same values, like no random on table 2 rows
How about switching to analytic ROW_NUMBER function? It doesn't really create a random value, but might be good enough.
Here's an example: first, create test tables and insert some data:
SQL> create table t1 (id number,address varchar2(20), town varchar2(10));
Table created.
SQL> create table t2 (id number, address varchar2(20), town varchar2(10));
Table created.
SQL> insert into t1
2 select 1, 'Ilica 20', 'Zagreb' from dual union all
3 select 2, 'Petrinjska 30', 'Sisak' from dual union all
4 select 3, 'Stradun 12', 'Dubrovnik' from dual;
3 rows created.
SQL> insert into t2
2 select 1, 'Pavelinska 15', 'Koprivnica' from dual union all
3 select 2, 'Baščaršija 11', 'Sarajevo' from dual union all
4 select 3, 'Riva 22', 'Split' from dual;
3 rows created.
SQL> select * From t1 order by id;
ID ADDRESS TOWN
---------- -------------------- ----------
1 Ilica 20 Zagreb
2 Petrinjska 30 Sisak
3 Stradun 12 Dubrovnik
SQL> select * From t2 order by id;
ID ADDRESS TOWN
---------- -------------------- ----------
1 Pavelinska 15 Koprivnica
2 Baščaršija 11 Sarajevo
3 Riva 22 Split
Update t1 with rows from t2:
SQL> update t1 set
2 (t1.address, t1.town) =
3 (select x.address, x.town
4 from (select row_number() over (order by address) id, t2.address, t2.town
5 from t2
6 ) x
7 where x.id = t1.id);
3 rows updated.
SQL> select * From t1 order by id;
ID ADDRESS TOWN
---------- -------------------- ----------
1 Baščaršija 11 Sarajevo
2 Pavelinska 15 Koprivnica
3 Riva 22 Split
SQL>

Need help in table creation with constraints

I have a requirement in which I have to create,
a person table with person id, Fname, Lname attributes
and also a person can be an employee or manager.
There is a constraint, a manager should be mapped to 1 or more emp (at least one emp).
Now, in this case, do we need to create a separate table for employee and manager and link it to person, if so how do we link both the table to person table and maintain the above-mentioned constraint
Note: There are no specific attributes for emp or manager table
That looks like a standard Scott's EMP table (if you're familiar with it). Something like this:
ID_EMP column is common to all persons
ID_MGR shows who is that person's manager
SQL> create table person
2 (id_emp number constraint pk_pers primary key,
3 fname varchar2(20),
4 lname varchar2(20),
5 id_mgr number constraint fk_mgr_emp references person (id_emp)
6 );
Table created.
SQL> insert into person (id_emp, fname, lname, id_mgr)
2 select 1, 'Little' , 'Foot' , null from dual union
3 select 2, 'Charles', 'Leclerc' , 1 from dual union
4 select 3, 'Rio' , 'Haryanto', 1 from dual union
5 select 4, 'Seb' , 'Vettel' , 2 from dual union
6 select 5, 'Romain' , 'Grosjean', 2 from dual;
5 rows created.
Hierarchical view:
SQL> select lpad(' ', 2 * level) || lname employee
2 from person
3 start with id_mgr is null
4 connect by prior id_emp = id_mgr;
EMPLOYEE
-------------------------------------------------------------------------------
Foot
Leclerc
Vettel
Grosjean
Haryanto
SQL>

How to use the union operator in oracle

I know that the union operator is used to (for example) return all rows from two tables after eliminating duplicates. Example:
SELECT a_id
FROM a
UNION
SELECT b_id
FROM b;
The result of listing of all elements in A and B eliminating duplicates is {1,2,3,4,5,6,7,8}.
If you joined A and B you would get only {4,5}. You would have to perform a full outer join to get the full list of 1-8. My question is if I wanted to use the union operator to display from a table called employees, the employee_id and job_id ( employee id being a number data type, and job_id being a VARCHAR2 data type) How would I go about doing this?
Would it be something like this: This does not run in oracle obviously,
SELECT employee_id
UNION
SELECT job_id
FROM employees;
If you really wanted to union together all the EMPLOYEE_IDs followed by all the JOB_IDs you'd use
SELECT TO_CHAR(EMPLOYEE_ID) FROM EMPLOYEES
UNION ALL
SELECT JOB_ID FROM EMPLOYEES
If you had rows with EMPLOYEE_IDs of 1, 2, and 3, and those same rows had JOB_IDs of 1, 11, and 111 you'd get a result set of six rows with a single column which would have values of
1
2
3
1
11
111
By using UNION ALL Oracle will allow the duplicates to pass through.
Share and enjoy.

Resources