Find duplicate records in a column and update the duplicates to max + 1 (oracle) - duplicates

I want to find the duplicate values and update the duplicated records with max(col1)+1 leaving the first record as is
example
create table tab1 (col1 number(10), col2 varchar2(50),col3 date);
/
insert into tab1(col1,col2) values(101,'sts');
insert into tab1(col1,col2) values(101,'sts');
insert into tab1(col1,col2) values(102,'gghh');
insert into tab1(col1,col2) values(102,'hhh');
insert into tab1(col1,col2) values(103,'sss');
insert into tab1(col1,col2) values(103,'dss');
insert into tab1(col1,col2) values(103,'ddd');
insert into tab1(col1,col2) values(777,'Aliens');
/
Select * from tab1;
result
101 sts
101 sts --duplicate
102 gghh
102 hhh --duplicate
103 sss
103 dss --duplicate
103 ddd --duplicate
777 Aliens
expected result after update (Which i am having difficulty achieving)
101 sts
102 gghh
103 sss
777 Aliens
778 sts --altered from 101
779 hhh --altered from 102
780 dss --altered from 103
781 ddd --altered from 103
This is what i have got to till now
DECLARE
v_cntr NUMBER := 0;
BEGIN
FOR rec IN (
SELECT rownumber,col1
from (SELECT ROW_NUMBER() OVER(PARTITION BY col1 ORDER BY col1) rownumber, col1
FROM tab1) X
WHERE rownumber > 1
)
LOOP
FOR rec2 IN (
SELECT ROWID FROM tab1 WHERE col1 = rec.col1
)
loop
v_cntr := v_cntr + 1;
UPDATE tab1
SET col1 = (Select max(col1)+1 from tab1)
WHERE rowid = rec2.rowid;
DBMS_OUTPUT.PUT_LINE ('done');
end LOOP;
END loop;
END;
Thanks All

I found the solution.
DECLARE
v_cntr NUMBER := 0;
BEGIN
FOR rec IN (
SELECT X.rownumber, X.rowid, X.col1
FROM (Select ROWID,col1, ROW_NUMBER() OVER(PARTITION BY col1 ORDER BY col1) as rownumber
FROM tab1) X
WHERE X.rownumber > 1
)
loop
v_cntr := v_cntr + 1;
UPDATE tab1
SET col1 = (Select max(col1)+1 from tab1)
WHERE rowid = rec.rowid;
DBMS_OUTPUT.PUT_LINE ('done');
END loop;
--COMMIT;
END;

Related

IF EXISTS with SQL Server 2008

I have a table order in which there are 3 columns
BookCode Quantity Billno
--------------------------
Ed001 2 A1
Ed002 3 A1
Ed003 1 A1
py001 5 A2
ed001 1 A2
ed005 2 A2
ed003 4 A2
Now I want to show my result to user as
table Result
BookCode A1 A2
----------------------
Ed001 2 1
Ed002 3 0
Ed003 1 4
py001 0 5
ed005 0 1
Result is my temporary table, I alter it and add column according to Billno
this works fine
Now I select BookCode and Quantity from table Order and insert it into result
What I want that if there is already a bookcode exist then just update result table otherwise insert a new row with that bookcode.
What should I do for that?
I solved it using Cursor..
create table #Result(BookCode varchar(20),BookRate float)
create table #bill(bilno varchar(max) )
insert into #bill ('A1')
insert into #bill ('A2')
SET #Ordnum = CURSOR FOR
SELECT bilno FROM #bill
OPEN #Ordnum
FETCH NEXT
FROM #Ordnum INTO #billno
WHILE ##FETCH_STATUS = 0
BEGIN
EXEC ('ALTER TABLE #temp ADD [' + #billno+ '] varchar(30)')
SET #getbookcode = CURSOR FOR
SELECT BookCode , BookQuantity , BookRate FROM OrderDetail where BillNo = #billno
OPEN #getbookcode
FETCH NEXT
FROM #getbookcode INTO #Tbookcode,#TbookQty,#TbookRate
WHILE ##FETCH_STATUS = 0
BEGIN
if exists(select BookCode from #Result where BookCode = #Tbookcode and BookRate = #TbookRate)
begin
EXEC('Update #Result set [' + #billno+']= '+#TbookQty+' where BookCode = '''+#Tbookcode+''' and BookRate = '+#TbookRate+'')
end
else
begin
EXEC('Insert Into #Result ([' + #bno + '],BookCode,BookRate) values ( '+#TbookQty +' , '''+#Tbookcode+''','+#TbookRate+')')
end
FETCH NEXT FROM #getbookcode INTO #Tbookcode,#TbookQty , #TbookRate
END
CLOSE #getbookcode
DEALLOCATE #getbookcode
FETCH NEXT FROM #Ordnum INTO #bno
END
CLOSE #Ordnum
DEALLOCATE #Ordnum
select * from #Result
Here #bill is a Temporary table in which Billnum are stored.
Use the MERGE statement. This does an INSERT or UPDATE based on the matching
Something like this, which includes the PIVOT needed
MERGE INTO result R
USING (
SELECT
ISNULL(O1.BookCode, O2.BookCode) AS BookCode,
ISNULL(O1.Quantity, 0) AS A1,
ISNULL(O2.Quantity, 0) AS A2
FROM
(SELECT * FROM #ORDER WHERE BillNo = 'A1') O1
FULL OUTER JOIN
(SELECT * FROM #ORDER WHERE BillNo = 'A2') O2
ON O1.BookCode = O2.BookCode
) src ON R.BookCode = src.BookCode
WHEN MATCHED THEN
UPDATE
SET A1 = src.A1, A2 = src.A2
WHEN NOT MATCHED BY TARGET THEN
INSERT (BookCode, A1, A2)
VALUES (src.BookCode, src.A1, src.A2);

mysql update line according to data from next line

I have this table in mysql:
name ID
B1 1
B2 1
B3 1
B4 2
B5 2
B6 2
A1 3
A2 3
A3 3
I'd like to add data into a column, notifying that the id will change at the next line. Something like this:
name beforeChange ID
B1 NO 1
B2 NO 1
B3 YES 1
B4 NO 2
B5 NO 2
B6 YES 2
A1 NO 3
A2 NO 3
A3 NO 3
A4 NO 3
Is there any way to do this in sql?
Thanks!
Ugly as sin & probably far from ideal from an efficiency point of view but seems to work:
create table myTable (id int(10) unsigned not null,name varchar(10));
insert into myTable (id,name) values (1,'B1');
insert into myTable (id,name) values (1,'B2');
insert into myTable (id,name) values (1,'B3');
insert into myTable (id,name) values (2,'B4');
insert into myTable (id,name) values (2,'B5');
insert into myTable (id,name) values (2,'B6');
insert into myTable (id,name) values (3,'A1');
insert into myTable (id,name) values (3,'A2');
insert into myTable (id,name) values (3,'A3');
insert into myTable (id,name) values (3,'A4');
select a.id,
case
when b.id is null then 'NO'
when b.id = (select max(id) from myTable) then 'NO' -- < handle last line of results set
else 'YES' end as beforeChange,a.name
from
-- rank within id
(
select mt.id,mt.name,
case mt.id when #curId then #curRow := #curRow + 1
else #curRow := 1 and #curId := mt.id END as rank
from myTable mt
join (select #curRow := 0, #curId := -1) r
order by id,name asc
) a
left outer join
-- max rank by id
(
select t.id,max(t.rank) as maxRank
from (
select mt.*,
case mt.id
when #curId
then #curRow := #curRow + 1
else #curRow := 1 and #curId := mt.id END
as rank
from myTable mt
join (select #curRow := 0, #curId := -1) r
order by id,name asc
) t
group by t.id
) b on a.id = b.id and b.maxRank = a.rank;

SQL/MYSQL Update child under parent till null

i have a database table like this.
userID RefralID balance
1 0 0
2 1 0
3 2 0
4 3 0
5 8 0
now i want a MYSQL query to update the balance of each child under userID 1.
stuck there from 10 hours, but couldn't find desired Solution.
Results should like this if we update balance=balance + 10 where userID = '1'
as the 2,3,4 are child and grand child of '1' so their balance should be updated
userID RefralID balance
1 0 0
2 1 10
3 2 10
4 3 10
5 8 0
update tblA T2 join
(
SELECT
#r AS _id,
(SELECT #r := userid FROM tblA WHERE refralid = _id limit 1) AS userid,
#l := #l + 1 AS lvl
FROM
(SELECT #r := 1, #l := 0) vars,
tblA m
) T1
ON T1._id = T2.userid
set balance=balance+10
where T2.userid<>1
#r := 1
T2.userid<>1
The value 1 above is the userid=1
Could remove the #l (level) as that is for reference.
http://sqlfiddle.com/#!2/e606a/2
The general approach is :
create table temp1 (int id);
create table temp2 (int id);
insert into temp1 select ReferalID from your_table where userID = 1
while exists (select 1 from temp1)
begin
truncate table temp2
update your_table
set balance = balance + 10
where userID in (select * from temp1)
insert into temp2 select * from temp1
truncate table temp1
insert into temp1
select ReferalID
from your_table
where userID in (select * from temp2)
end

A better solution to replace an old cursor?

I have two tables like this
table1 sorted by paymentid, paydate:
paymentid paydate amount
1 20120101 100
1 20120101 150
1 20120101 150
2 20120115 100
2 20120115 100
...
table2 sorted by paymentid, paydate:
paymentid paydate pay1 pay2 pay3....base on the position from table1...up to pay20
1 20120101 null null null
2 20120115 null null null
...
after update, table2 should be like this
1 20120101 100 100 150 null.....
2 20120115 100 100 null null null.....
The possible solutions i can come up so far are:
1, a temp table for looping thru table1
2, a cursor...current solution:
declare #paymentid int
declare #paydate char(10)
declare #amount money
declare #count int
declare #saveid int
declare #savedate char(10)
delcare cur cursor for select paymentid, paydate, amount from table1 order by paymentid, paydate
open cur
fetch next from cur into #paymentid,#paydate,#amount
while ##fetch_status = 0
if #saveid <> #paymentid or #savedate <> #paydate
set #count = 1
set #saveid = #paymentid
set #savedate = #paydate
else set #count = #count + 1
if #count = 1
update table2
set pay1 = #amount
where paymentid = #paymentid and paydate = #paydate
if #count = 2
update table2
set pay2 = #amount
...
fetch next
...
Any suggestion will be appreciated.
Try this
SQL Fiddle
declare #Test Table (paymentid int,
paydate varchar(25), amount int)
INSERT INTO #Test
SELECT 1,'20120101',100
UNION ALL
SELECT 1,'20120101',150
UNION ALL
SELECT 1,'20120101',150
UNION ALL
SELECT 2,'20120115',100
UNION ALL
SELECT 2,'20120115',100
--INSERT into Table2 //insert here
SELECT * FROM (
SELECT *, 'pay' + CAST(Row_Number() OVER (Partition by paymentid,
paydate order by amount) AS VARCHAR) PayCol
FROM #Test
) V
PIVOT
(
MAX(Amount) For PayCol IN
(pay1,pay2,pay3,pay4, pay5, pay6, pay7, pay8, pay9, pay10,
pay11,pay12,pay13,pay14, pay15, pay16, pay17, pay18, pay19, pay20)
) As P

SQL SERVER generating row number based on criteria

I have a table which has columns UserID,DIFFTIME. when I select these columns from the table, I also want to have a derived column which is : If the DiffTime is > 20 I want to increment the count per user id.
For example if the table has:
User ID DIFF TIME
1 0
1 5
1 10
2 0
2 21
2 5
I want a result set that is something like this:
User ID DIFF TIME SESSION NUMBER
1 0 1
1 5 1
1 10 1
2 0 1
2 21 2
2 5 2
How do I accomplish this.
Ideas and suggestions are much appreciated!
Use this statement:
select t1.User_Id, t1.Diff_Time,
isnull(count(t2.User_Id), 0) + 1 as Session_Number
from #table t1
left join #table t2
on t1.User_Id = t2.User_Id
and t1.eventTime >= t2.eventTime
and t2.Diff_Time > 20
group by t1.User_Id, t1.Diff_Time, t1.eventTime
order by t1.User_Id, t1.eventTime
(replace #table with your actual table name)
Note: I assume that the fifth row of your table has the value 21 in the Diff_Time column, and there's a typo in the question, as #AaronBertrand pointed out in the comments
create table #t
(
id int,
Diff int,
SessionNumber int
)
insert into #t(id, diff)values(1, 0)
insert into #t(id, diff)values(1, 5)
insert into #t(id, diff)values(1, 10)
insert into #t(id, diff)values(2, 0)
insert into #t(id, diff)values(2, 21)
insert into #t(id, diff)values(2, 5)
Select ROW_NUMBER() over(order by Id) as RowID, * into #Temp1 from #t
Declare #diff int
Declare #RowId int
Declare #Previous int
Declare #NewValue int
DECLARE #Cur CURSOR SET #Cur = CURSOR FOR select RowId, diff from #Temp1
OPEN #Cur
FETCH NEXT FROM #Cur INTO #RowId, #diff
WHILE ##FETCH_STATUS = 0
BEGIN
if(#RowId = 1)
Begin
Update #Temp1 Set SessionNumber = 1 Where rowid = 1
Set #Previous = #Diff
Set #NewValue = 1
End
Else
Begin
if(#Diff - #Previous > 20)
Begin
Set #Previous = #Diff
Set #NewValue = #NewValue + 1
Update #Temp1 Set SessionNumber = #NewValue Where rowid = #RowId
End
else
Update #Temp1 Set SessionNumber = #NewValue Where rowid = #RowId
End
FETCH NEXT FROM #Cur INTO #RowId, #diff
END
CLOSE #Cur
DEALLOCATE #Cur
select * from #temp1
drop table #t
drop table #temp1