I'm very new to pl/sql and I cannot make this query run.
I want it to find differences between two tables and then output ID of those transactions.
Any help would be appreciated!
SET SERVEROUTPUT ON
DECLARE
diff_id varchar2(50);
diff_id2 varchar2(50);
BEGIN
FOR dcount IN
SELECT
O.transid ,
ABB.transid
into diff_id, diff_id2
FROM
(SELECT *
FROM O.transactions
AND abdate >= trunc(sysdate -3)
) O
FULL OUTER JOIN
(SELECT *
FROM ABB.transactions
AND abdate >= trunc(sysdate -3)
) ABB
ON O.transid = ABB.transid
LOOP
DBMS_OUTPUT.put_line (employee_rec.diff_id);
DBMS_OUTPUT.put_line (employee_rec.diff_id2);
END LOOP;
END;
my desired output would be id of transactions which are not in both
tables. Ie 375 and 480
Ah, yes, 375 and 480. What about 832?
Anyway: you don't need PL/SQL to do that. Would SET operators do any good? For example, if you want to fetch ID s from the first table that aren't contained in the second one, you'd use
select id from first_table
minus
select id from second_table;
Both ways?
select 'in 1st, not in 2nd' what, id
from (select id from first_table
minus
select id from second_table)
union all
select 'in 2nd, not in 1st', id
from (select id from second_table
minus
select id from first_table);
Apply additional conditions, if necessary (ABDATE column, for example).
Related
select count(*)
INTO countExceed
from uid_emp_master k
where k.unique_id in (select k.reviewer_uid
from uid_rm_hierarchy k
where k.unique_id in ('||p_ID_list||'))
and k.band IN( 'A','B','C','D');
if (countExceed > 0) then
quer :='UPDATE UID_RM_HIERARCHY I
SET I.REVIEWER_UID in (SELECT L.REVIEWER_UID
FROM UID_RM_HIERARCHY L
WHERE L.UNIQUE_ID in ('||p_ID_list||') )
WHERE I.REVIEWER_UID in('||p_ID_list||')
and isdeleted=0';
EXECUTE IMMEDIATE quer ;
END IF;
the above stored procedure does not show any result the variable countExceed declared as a number please help me to correct the query.
The issue is in
where k.unique_id in ('||p_ID_list||'))
Here you are saying to look for records
where unique_id = '||p_ID_list||'
exactly as its typed, but what you need is to handle that variable as a list of values.
Say you have a table like this
create table tabTest(id) as (
select 'id1' from dual union all
select 'id2' from dual union all
select 'id3' from dual union all
select 'id4' from dual
)
and your input string is 'id1,id3,1d8';
I see two ways to do what you need; one is with dynamic SQL, for example:
declare
vResult number;
vList varchar2(199) := 'id1,id3,1d8';
vSQL varchar2(100);
begin
vSQL :=
'select count(*)
from tabTest
where id in (''' || replace (vList, ',', ''', ''') || ''')';
--
execute immediate vSQL into vResult;
--
dbms_output.put_line('Result: ' || vResult);
end;
Another way could be by splitting the string into a list of values and then simply using the resulting list in the IN.
For that, there are many answers about how to split a comma separated list string in Oracle.
I have a oracle query
select id from (
select ID, ROW_NUMBER() over (partition by LATEST_RECEIPT order by ID) rownumber
from Table
where LATEST_RECEIPT in
(
select LATEST_RECEIPT from Table
group by LATEST_RECEIPT
having COUNT(1) > 1
)
) t
where rownumber <> 1;
The data type of LATEST_RECEIPT was earlier varchar2(4000) and this query worked fine. Since the length of the column needs to be extended i modified it to CLOB, after which this fails. Could anyone help me fix this issue or provide a work around?
You can change your inner query to look for other rows with the same last_receipt value but a different ID (assuming ID is unique); if another row exists then that is equivalent to your count returning greater than one. But you can't simply test two CLOB values for equality, you need to use dbms_lob.compare:
select ID
from your_table t1
where exists (
select null from your_table t2
where dbms_lob.compare(t2.LATEST_RECEIPT, t1.LATEST_RECEIPT) = 0
and t2.ID != t1.ID
-- or if ID isn't unique: and t2.ROWID != t1.ROWID
);
Applying the row number filter is tricker, as you also can't use a CLOB in the analytic partition by clause. As André Schild suggested, you can use a hash; here passing the integer value 3, which is the equivalent of dbms_crypto.hash_sh1 (though in theory that could change in a future release!):
select id from (
select ID, ROW_NUMBER() over (partition by dbms_crypto.hash(LATEST_RECEIPT, 3)
order by ID) rownumber
from your_table t1
where exists (
select null from your_table t2
where dbms_lob.compare(t2.LATEST_RECEIPT, t1.LATEST_RECEIPT) = 0
and t2.ID != t1.ID
-- or if ID isn't unique: and t2.ROWID != t1.ROWID
)
)
where rownumber > 1;
It is of course possible to get a hash collision, and if that happened - you had two latest_receipt values which both appeared more than once and both hashed to the same value - then you could get too many rows back. That seems pretty unlikely, but it's something to consider.
So rather than ordering you can only look for rows which have the same lastest_receipt and a lower ID:
select ID
from your_table t1
where exists (
select null from your_table t2
where dbms_lob.compare(t2.LATEST_RECEIPT, t1.LATEST_RECEIPT) = 0
and t2.ID < t1.ID
);
Again that assumes ID is unique. If it isn't then you could still use rowid instead, but you would have less control over which rows were found - the lowest rowid isn't necessarily the lowest ID. Presumably you're using this to dine rows to delete. If you actually don't mind which row you keep and which you delete then you could still do:
and t2.ROWID < t1.ROWID
But since you are currently ordering that probably isn't acceptable, and hashing might be preferable, despite the small risk.
Example:
It does not work.
UPDATE column_name SET rownum FROM table_name
This work!
UPDATE table_name SET column_name = rownum;
This works but the update is performed incorrectly
SELECT * FROM table_name ORDER BY column_name;
UPDATE table_name SET column_name = rownum;
I wish the following update behavior:
Note:'rownum ' It is not a physical column of the table
/*
pc_comentario = tableName
cod_comentario = columnName (Reference column for sorting)
dtc_andamento = columnDay (Reference column to update the "columnName" according to the order of this column)
*/
rownum | columnName | columnDay
1 1 day 1
2 5 day 5
3 7 day 2
After change with update
rownum | columnName (Update this column) | columnDay (sort by this column)
1 1 day 1
2 2 day 2
3 3 day 5
ALMOST DONE! this column 'cod_comentario_1 "which was materialized in RAM is correct. I need this column" cod_comentario_1 "that does not exist in the table is acknowledged in the consultations with java.
SELECT cod_comentario, dtc_andamento, cod_processo ,
ROW_NUMBER()
OVER (PARTITION BY cod_processo
ORDER BY dtc_andamento) cod_comentario_1
FROM pc_comentario
upadate do not work this way:
UPDATE (
SELECT cod_processo
ROW_NUMBER()
OVER (PARTITION BY cod_processo
ORDER BY dtc_andamento)cod_comentario_1
FROM pc_comentario
) SET cod_comentario_1)
order by Seq
I must enter the values of this consultation in a new column that I created
SELECT
ROW_NUMBER()
OVER (PARTITION BY cod_processo
ORDER BY dtc_andamento DESC)
FROM pc_comentario
Try:
UPDATE table_name
SET column_name = rownum
Shouldn't it be like below rather; I believe UPDATE statement has no FROM clause
UPDATE table_name SET column_name = rownum;
Again, it will work only if rownum is an existing column in your table. If you are trying to use Oracle rownum instead then consider using row_number() function rather
update table_name set column_name =
select rn from ( select column_name, row_number() over (order by column_name) rn
from table_name ) xx;
As you state yourself, rownum is a virtual column. It assigns a sequential value to each row of a particular result set. Which means that the row number of a row could be completely different in the result set of a different query.
If you really want to show the row number as part of the result set, specify it as you would any column:
select rownum as columnName, columnDay
from table
order by ...;
I have a table employee has 30000 records. I need to delete duplicate records based on two columns concatenation. For example name and job, like
martin clerk
martin clerk
Below is my code:
declare
type typ_emp is table of emp%rowtype;
v_emp typ_emp;
cursor cur_emp
is
select *
from emp a
where rowid >
(select min (rowid)
from emp b
where concat (concat (b.ename, '-'), b.job) =
concat (concat (a.ename, '-'), a.job)
)
;
begin
open cur_emp;
loop
fetch cur_emp bulk collect into v_emp;
exit when v_emp.count = 0;
if v_emp.count > 0
then
for i in v_emp.first .. v_emp.last
loop
insert into backup_emp (ename, job)
values (v_emp (i).ename, v_emp (i).job)
;
end loop;
end if;
end loop;
close cur_emp;
delete
from emp s
where s.rowid >
any (select t.rowid
from emp t
where concat (concat (t.ename, '-'), t.job) =
concat (concat (s.ename, '-'), s.job));
commit;
exception
when others then
Raise;
end;
It is taking a long time to delete the records. Can anyone help me in tuning a query for this or suggest me what is the better approach.
Thanks in advance.
Creating function based index might improve your performance
CREATE INDEX concatindex ON emp (ename||'-'||job);
Delete statement would look like this
delete emp a where a.rowid > (select min(rowid) from emp b where b.ename||'-'||b.job=a.ename||'-'||a.job)
unless you need to insert deleted rows into backup table which is not clear from your question. If so I would rather bulkcollect rows into collection. Leave a comment if you need to have detailed this option.
I hope this helps.
SELECT ROWID, ename || '-' || job AS concatenation,
decode(rank() over(PARTITION BY ename || '-' || job ORDER BY ROWID), 1, 'keep', 'delete') AS to_do
FROM emp
ORDER BY ename || '-' || job, ROWID;
Here is my code changes:
cursor cur_emp
is
select *
from
(select b.*
,row_number()over(partition by concat (concat (b.ename, '-'), b.job) order by ename)cnt
from emp b
) where cnt>1;
We have a table which has three columns in it:
Customer_name, Age_range, Number_of_people.
1 1-5 10
1 5-10 15
We need to return all the number of people in different age ranges as rows of a single query. If we search for customer #1, the query should just return one row:
Header- Age Range (1-5) Age Range (5-10)
10 15
We needed to get all the results in a single row; When I query for customer 1, the result should be only number of people in a single row group by age_range.
What would be the best way to approach this?
You need to manually perform a pivot:
SELECT SUM(CASE WHEN age_range = '5-10'
THEN number_of_people
ELSE NULL END) AS nop5,
SUM(CASE WHEN age_range = '10-15'
THEN number_of_people
ELSE NULL END) AS nop10
FROM customers
WHERE customer_name = 1;
There are easy solutions with 10g and 11g using LISTGAGG, COLLECT, or other capabilities added after 9i but I believe that the following will work in 9i.
Source (http://www.williamrobertson.net/documents/one-row.html)
You will just need to replace deptno with customer_name and ename with Number_of_people
SELECT deptno,
LTRIM(SYS_CONNECT_BY_PATH(ename,','))
FROM ( SELECT deptno,
ename,
ROW_NUMBER() OVER (PARTITION BY deptno ORDER BY ename) -1 AS seq
FROM emp )
WHERE connect_by_isleaf = 1
CONNECT BY seq = PRIOR seq +1 AND deptno = PRIOR deptno
START WITH seq = 1;
DEPTNO CONCATENATED
---------- --------------------------------------------------
10 CLARK,KING,MILLER
20 ADAMS,FORD,JONES,SCOTT,SMITH
30 ALLEN,BLAKE,JAMES,MARTIN,TURNER,WARD
3 rows selected.
This will create a stored FUNCTION which means you can access it at any time.
CREATE OR REPLACE FUNCTION number_of_people(p_customer_name VARCHAR2)
RETURN VARCHAR2
IS
v_number_of_people NUMBER;
v_result VARCHAR2(500);
CURSOR c1
IS
SELECT Number_of_people FROM the_table WHERE Customer_name = p_customer_name;
BEGIN
OPEN c1;
LOOP
FETCH c1 INTO v_number_of_people;
EXIT WHEN c1%NOTFOUND;
v_result := v_result || v_number_of_people || ' ' || CHR(13);
END;
END;
To run it, use:
SELECT number_of_people(1) INTO dual;
Hope this helps, and please let me know if there are any errors, I didn't testrun the function myself.
Just do
select Number_of_people
from table
where Customer_name = 1
Are we missing some detail?