Oracle Comma Separated Value (ID) in a Column. How to get Description for each Value in a Comma Separated string. - oracle

Sorry for the Confusing title.I myself did not understand it when i read it second time.
So here is the details description.
I have a table say "Awards" which have following Column:
Name,
Amount,
Employee
and Another table "Employee" which have following column:
Emp_Id,
Emp_Name
and in employee column of "Awards" table i have value "01,20" which are actually the Employee ID referenced to "Employee" table.
So is there any way i can get Employee Name in select "Awards" query?

Here is one method:
select a.*, e.EmpName
from Awards a join
Employees e
on ','||a.employee||',' like '%,'||e.emp_id||',%';
This will return the employee names on separate lines. If you want them in a list, then you would need to concatenate them together (and the best function for doing that depends on your version of Oracle).
By the way, this is a very bad data structure, You should have an association table AwardEmployee that has one row for each row and each employee.

Given below is the query to get comma seperated employee ids in form of rows which I put in subquery to get their name. Please edit as per your ewquirements.
Select Ename from employee where employee_id in (
SELECT trim(x.column_value.extract('e/text()')) COLUMNS
from awards t, table (xmlsequence(xmltype('<e><e>' || replace(Employee,':','</e><e>')||
'</e></e>').extract('e/e'))) x )

I have changed the Database (added one more table). and already started changing the CODE, as for the said report i have used following
WITH t AS
(
Select emp_name from employee where emp_id in (
select regexp_substr(Employee ,'[^,]+', 1, level) from awards
connect by regexp_substr((select Employee from awards ), '[^,]+', 1, level) is
not null)
)
SELECT LTRIM(SYS_CONNECT_BY_PATH(emp_name, ','),',') emp_name
FROM ( SELECT emp_name,
ROW_NUMBER() OVER (ORDER BY emp_name) FILA
FROM t )
WHERE CONNECT_BY_ISLEAF = 1
START WITH FILA = 1
CONNECT BY PRIOR FILA = FILA - 1
Which is temporary and i understand very less of it.
Thanks for you help and suggestion.

Related

Fetch single record from duplicate rows from oracle table

I have a table user_audit_records_tbl which has multiple rows for a single user ,Every time user logs in one entry is made into this table so i want a select query which will fetch a latest single record for each user, I have a query which uses IN clause.
Table Name : user_audit_records_tbl
Record_id Number Primary Key,
user_id varchar Primary Key ,
user_ip varchar,
.
.
etc
Current query i am using is
select * from user_audit_records_tbl where record_id in (select
max(record_id) from user_audit_records_tbl
group by user_id);
but was just wondering if anybody has better solution for this since this table has huge volumns.
You can use the first/last function
select max(Record_id) as Record_id,
user_id,
max(user_ip) keep (dense_rank last order by record_id) as user_ip,
...
from user_audit_records_tbl
group by user_id
No sure if it will be more efficient.
EDIT : As above query is less efficient, may be you could try an exist clause
select *
from user_audit_records_tbl A
where exists ( select 1
from user_audit_records_tbl B
where A.user_id = B.user_id
group by B.user_id
having max(B.record_id) = A.record_id
)
But maybe, you should look on the index side instead of the query side.
select *
from ( select row_number() over ( partition by user_id order by record_id desc) row_nr,
a.*
from user_audit_records_tbl a
)
where row_nr = 1
;

MERGING DATA OF TWO TABLES

I want to write a query which finds the difference between two tables and writes updates or new data into third table. My two tables have identical column names. Third table which captures changes have extra column called comment. I would like to insert the comment whether it is a new row or updated row based on the row modification.
**TABLE1 (BACKUP)**
KEY,FIRST_NAME,LAST_NAME,CITY
1,RAM,KUMAR,INDIA
2,TOM,MOODY,ENGLAND
3,MOHAMMAD,HAFEEZ,PAKISTAN
4,MONIKA,SAM,USA
5,MIKE,PALEDINO,USA
**TABLE2 (CURRENT)**
KEY,FIRST_NAME,LAST_NAME,CITY
1,RAM,KUMAR,USA
2,TOM,MOODY,ENGLAND
3,MOHAMMAD,HAFEEZ,PAKISTAN
4,MONIKA,SAM,INDIA
5,MIKE,PALEDINO,USA
6,MAHELA,JAYA,SL
**TABLE3 (DIFFERENCE FROM TABLE2 TO TABLE1)**
KEY,FIRST_NAME,LAST_NAME,CITY,COMMENT
1,RAM,KUMAR,USA,UPDATE
4,MONIKA,SAM,INDIA,UPDATE
6,MAHELA,JAYA,SL,INSERT
table scripts
DROP TABLE TABLE1;
DROP TABLE TABLE2;
DROP TABLE TABLE3;
CREATE TABLE TABLE1
(
KEY NUMBER,
FIRST_NAME VARCHAR2(100),
LAST_NAME VARCHAR2(100),
CITY VARCHAR2(50)
);
/
CREATE TABLE TABLE2
(
KEY NUMBER,
FIRST_NAME VARCHAR2(100),
LAST_NAME VARCHAR2(100),
CITY VARCHAR2(50)
);
/
CREATE TABLE TABLE3
(
KEY NUMBER,
FIRST_NAME VARCHAR2(100),
LAST_NAME VARCHAR2(100),
CITY VARCHAR2(50),
COMMENTS VARCHAR2(200)
);
/
INSERT ALL
INTO TABLE1
VALUES(1,'RAM','KUMAR','INDIA')
INTO TABLE1 VALUES(2,'TOM','MOODY','ENGLAND')
INTO TABLE1 VALUES(3,'MOHAMMAD','HAFEEZ','PAKISTAN')
INTO TABLE1 VALUES(4,'MONIKA','SAM','USA')
INTO TABLE1 VALUES(5,'MIKE','PALEDINO','USA')
SELECT 1 FROM DUAL;
/
INSERT ALL
INTO TABLE2
VALUES(1,'RAM','KUMAR','USA')
INTO TABLE2 VALUES(2,'TOM','MOODY','ENGLAND')
INTO TABLE2 VALUES(3,'MOHAMMAD','HAFEEZ','PAKISTAN')
INTO TABLE2 VALUES(4,'MONIKA','SAM','INDIA')
INTO TABLE2 VALUES(5,'MIKE','PALEDINO','USA')
INTO TABLE2 VALUES(6,'MAHELA','JAYA','SL')
SELECT 1 FROM DUAL;
I was using the merge statement to accomplish the same. but i have hit a roadblock in merge statement , it's rhrowing an error "SQL Error: ORA-00905: missing keyword
00905. 00000 - "missing keyword"" I dont understand where is the error. please help
INSERT INTO TABLE3
SELECT KEY,FIRST_NAME,LAST_NAME,CITY,NULL AS COMMENTS FROM TABLE2
MINUS
SELECT KEY,FIRST_NAME,LAST_NAME,CITY,NULL AS COMMENTS FROM TABLE1
;
MERGE INTO TABLE3 A
USING TABLE1 B
ON (A.KEY=B.KEY)
WHEN MATCHED THEN
UPDATE SET A.COMMENTS='UPDATED'
WHEN NOT MATCHED THEN
UPDATE SET A.COMMENTS='INSERTED';
There is no such WHEN NOT MATCHED THEN UPDATE clause, you should use WHEN NOT MATCHED THEN INSERT. Refer to MERGE for details.
A few assumptions made about the data:
An INSERT event will be a record identified by its key in table2 (current data) that does not have a matching key in the original back-up table: table1.
An UPDATE event is a field that exists in both table1 and table2 for the same KEY but is not the same.
Records which did not change between tables are not to be recorded in table3.
Example Query: Check for Updates
SELECT UPD_QUERY.NEW_CITY, 'UPDATED' as COMMENTS
FROM (SELECT CASE WHEN REPLACE(CURR.CITY, BKUP.CITY,'') IS NOT NULL THEN CURR.CITY
ELSE NULL END as NEW_CITY
FROM table1 BKUP, table2 CURR
WHERE BKUP.KEY = CURR.KEY) UPD_QUERY
WHERE UPD_QUERY.NEW_CITY is NOT NULL;
You can repeat this comparison method for the other fields:
SELECT UPD_QUERY.*
FROM (SELECT CURR.KEY,
CASE WHEN REPLACE(CURR.FIRST_NAME, BKUP.FIRST_NAME,'') IS NOT NULL
THEN CURR.FIRST_NAME
ELSE NULL END as FIRST_NAME,
CASE WHEN REPLACE(CURR.LAST_NAME, BKUP.LAST_NAME,'') IS NOT NULL
THEN CURR.LAST_NAME
ELSE NULL END as LAST_NAME,
CASE WHEN REPLACE(CURR.CITY, BKUP.CITY,'') IS NOT NULL
THEN CURR.CITY
ELSE NULL END as CITY
FROM table1 BKUP, table2 CURR
WHERE BKUP.KEY = CURR.KEY) UPD_QUERY
WHERE COALESCE(UPD_QUERY.FIRST_NAME, UPD_QUERY.LAST_NAME, UPD_QUERY.CITY)
is NOT NULL;
NOTE: This could get unwieldy very quickly if the number of columns compared are many. Since the target table design (table3) requires not only identification of a change, but the field and its new value are also recorded.
Example Query: Look for Newly Added Records
SELECT CURR.*, 'INSERTED' as COMMENTS
FROM table2 CURR, table1 BKUP
WHERE CURR.KEY = BKUP.KEY(+)
AND BKUP.KEY is NULL;
Basically MERGE forces the operation: MATCHED=UPDATE (or DELETE), NOT MATCHED = INSERT. It's in the docs.
You can do what you want but you need two insert statements with different set operators,
For UPDATED:
Insert into table3
table1 INTERSECT table2
For INSERTED:
Insert into table3
table2 MINUS table1

How to clear table in oracle

I have data table in Oracle 8,1. There are about a million rows. But lots of rows duplicates by the same columns. I need to know fastest way to clear this data.
For example I have:
id name surname date
21 'john' 'smith' '2012 12 12';
21 'john' 'smith' '2012 12 13';
21 'john' 'smith' '2012 12 14';
....
And now I need to delete first two rows as they duplicates by first three columns and keep the row with the latest date.
If there are really lots of duplicates, I'd recommend to recreate the table with only the clean data:
CREATE TABLE tmp AS
SELECT id, name, surname, max(d) as d
FROM t
GROUP BY id, name, surname;
and then replace the original table with the original table:
RENAME your_table TO old_table;
RENAME tmp_table TO your_table;
Don't forget to move indexes, constraints and privileges...
delete from table t where
exists (select * from table where id=t.id and name=t.name and surname=t.surname
and date > t.date)
How fast this is depends con your Oracle parameters. And index on (id,name,surname) might help.
If possible, I'd go for a CTAS (create table as select), truncate the original table, and copy the data back:
-- create the temp table (it contains only the latest values for a given (id, name, surname) triple
CREATE TABLE tmp as
SELECT id, name, surname, date1 from
(select
t1.*,
row_number() over (partition by id, name, surname order by date1 desc) rn
from mytab t1)
where rn = 1;
-- clear the original table
TRUNCATE TABLE mytab;
-- copy the data back
INSERT /* +APPEND */ INTO mytab(id,name,surname,date1)
(SELECT id,name,surname,date1 from tmp);

ORACLE: How to select previous different value?

I have table that stores employee job name, it has the following columns:
id; date_from; date_to; emp_id; jobname_id; grade;
Each emp_id can have many consecutive records with the same jobname_id due to many grade changes.
How can I select previous different jobname_id omitting those that are the same like the most current one?
This solution uses the FIRST_VALUE() analytic function to identify each employee's current job. It then filters for all the jobs which dfon't match that one:
select distinct id
, jobname_id
from ( select id
, jobname_id
, first_value(jobname_id) over (partition by id
order by from_date desc) as current_job
from employee
where emp_id = 1234 )
where jobname_id != current_job
order by id, jobname_id
/
Will this work for your issue:
SELECT DISTINCT
e1.emp_id,
e1.jobname_id
FROM employee e1
WHERE NOT EXISTS
(SELECT 1
FROM employee e2
WHERE e1.emp_id = e2.emp_id
AND SYSDATE BETWEEN e2.date_from
AND NVL(e2.date_to, SYSDATE + 1));
(This asumes your table is named "employee" and emp_id is the PK value).
It selects unique emp_id, jobname_id values where the emp_id, jobname_id values are not current.
EDIT: I agree with Chin Boon that fundamentally this is a design issue and perhaps that should be addressed rather than working around the problem.

Oracle multiple inserts, different ids

I want to move some data from one table to another. I wrote a query that I think will work, but in the destination table, there is a column that contains an id. I want each row I insert to have a different and consecutive id. Here is a simplificated example:
Table1
Name Telephone Actie
Peter 123456 Y
Michael 111111 Y
George 1234445 N
Table2
Id Name Likes
1 Peter Books
2 Michael Books
The query I wrote:
insert all into table2 (name, likes)
select all.name name, 'Books' likes, from (select o.name
from table1 o where o.active='Y') all;
Is there any way of generating the consecutive ids and use the "insert all into" query? A sequence? If it can be made with a sequence... is there any way of doing it without a sequence?
Thanks and regards!
The proper way to generate id's in Oracle is by using a sequence.
create sequence seq_table2_id nocache;
Then upon inserting call seq_table2_id.nextval.
insert into table2 (id, name, likes)
select seq_table2_id.nextval
, o.name
, 'Books'
from table1 o
where o.active = 'Y'
Personally I use a trigger to automatically call the sequence on inserts, but there are people who dislike using triggers.
You can use ROWNUM:
insert into table2 (id, name, likes)
select ROWNUM, all.name name, 'Books' likes from (select o.name
from table1 o where o.active='Y') all;
I'm not sure why you have the subquery (perhaps your real query is more complex?) You could write:
insert into table2 (id, name, likes)
select ROWNUM, o.name, 'Books' likes
from table1 o where o.active='Y';

Resources