August 21, 2006 at 8:37 am
Hello,
First let me qualify this-I'm fairly new at SQL and programming in general. My training has been trial by fire so far 🙂
I have a SQL table with a field called pos_no. The field pos_no currently has a 6 digit number in it, such as 100001. Out of 200 records in the table there may be 20 with the same value in the pos_no field. For example, it may look like this:
100001
100001
540053
550008
550008
550008
883500
Some are duplicates but some are unique.
I'd like to write a script that appends a -XXX to the end of each one, and counts up one for each previous value that is the same. For example, I'd like it to look like this:
100001-001
100001-002
540053-001
550008-001
550008-002
550008-003
883500-001
Any help or pointers in the right direction would be greatly appreciated.
Thanks!
August 21, 2006 at 10:05 am
Hi,
I'm sure there's a better way of doing this using joins but this is all I can come up with for now:
set nocount on
create table #test1 (accno varchar(50))
create table #test2 (seq int identity(1,1), accno2 varchar(50))
insert #test1 values (100001)
insert #test1 values (100001)
insert #test1 values (100048)
insert #test1 values (100001)
insert #test1 values (100002)
insert #test1 values (100001)
insert #test1 values (200567)
insert #test1 values (345000)
insert #test1 values (345000)
insert #test1 values (456730)
insert #test1 values (234555)
insert #test1 values (456730)
insert #test1 values (112233)
insert #test1 values (112233)
insert #test1 values (443322)
insert #test1 values (334455)
insert #test1 values (112233)
insert #test1 values (443322)
insert #test1 values (112233)
insert #test1 values (334455)
insert into #test2 (accno2)
select accno from #test1 order by accno
declare @increment int, @current varchar(50), @previous varchar(50), @min-2 int, @max-2 int
select @increment=0,
@previous='000000',
@min-2=(select min(seq) from #test2),
@max-2=(select max(seq) from #test2)
while @max-2>=@min
BEGIN
select @current=(select accno2 from #test2 where seq=@min)
if @current = @previous
select @increment=@increment+1
else
select @increment=1
print @current + '-' + right('000' + cast(@increment as varchar) , 3)
select @previous=@current, @min-2=@min+1
END
drop table #test1
drop table #test2
-----------------
You should be able to replace the print command with an update etc if necessary.
August 21, 2006 at 10:10 am
You may try this
DECLARE @tbl TABLE
(ActualValue VARCHAR(30),
UpdatedValue VARCHAR(20))
INSERT INTO @tbl(ActualValue) vALUES (100001)
INSERT INTO @tbl(ActualValue) vALUES (100001)
INSERT INTO @tbl(ActualValue) vALUES (100048)
INSERT INTO @tbl(ActualValue) vALUES (100001)
INSERT INTO @tbl(ActualValue) vALUES (100002)
INSERT INTO @tbl(ActualValue) vALUES (100001)
INSERT INTO @tbl(ActualValue) vALUES (200567)
INSERT INTO @tbl(ActualValue) vALUES (345000)
INSERT INTO @tbl(ActualValue) vALUES (345000)
INSERT INTO @tbl(ActualValue) vALUES (456730)
INSERT INTO @tbl(ActualValue) vALUES (234555)
INSERT INTO @tbl(ActualValue) vALUES (456730)
INSERT INTO @tbl(ActualValue) vALUES (112233)
INSERT INTO @tbl(ActualValue) vALUES (112233)
INSERT INTO @tbl(ActualValue) vALUES (443322)
INSERT INTO @tbl(ActualValue) vALUES (334455)
INSERT INTO @tbl(ActualValue) vALUES (112233)
INSERT INTO @tbl(ActualValue) vALUES (443322)
INSERT INTO @tbl(ActualValue) vALUES (112233)
INSERT INTO @tbl(ActualValue) vALUES (334455)
DECLARE @RowId VARCHAR(20)
DECLARE @UpdatedValue INT
UPDATE Source
SET @UpdatedValue = (CASE
WHEN @RowId = ISNULL(Source.ActualValue,0) THEN ISNULL(@UpdatedValue,0)+1
ELSE ISNULL(Source.UpdatedValue,0)
END),
Source.UpdatedValue = ActualValue+'-'+REPLICATE('0',3-LEN(LTRIM(RTRIM(@UpdatedValue))))+CAST(@UpdatedValue AS VARCHAR(10)),
@RowId = ISNULL(Source.ActualValue,0)
FROM @tbl AS Source
SELECT * FROM @tbl
Ram
August 21, 2006 at 10:12 am
declare @t table (srno int)
insert into @t values (100001)
insert into @t values (100001)
insert into @t values (540053)
insert into @t values (550008)
insert into @t values (550008)
insert into @t values (550008)
insert into @t values (883500)
update
a
set
a.Srno = cast(a.Srno as varchar) + (REPLICATE('0', 2))+ cast(b.Seq# as varchar)
from
(select row_number() over(partition by srno order by srno) Seq#, Srno from @t)a
join
(select row_number() over(partition by srno order by srno) Seq#, Srno from @t) b
on
a.Srno = b.Srno
and a.Seq# = b.Seq#
select * from @t
August 21, 2006 at 10:18 am
My Script requires ordering of records before update and hence
DECLARE @tbl1 TABLE
(ActualValue VARCHAR(30),
UpdatedValue VARCHAR(20))
DECLARE @tbl TABLE
(ActualValue VARCHAR(30),
UpdatedValue VARCHAR(20))
INSERT INTO @tbl1(ActualValue) vALUES (100001)
INSERT INTO @tbl1(ActualValue) vALUES (100001)
INSERT INTO @tbl1(ActualValue) vALUES (100048)
INSERT INTO @tbl1(ActualValue) vALUES (100001)
INSERT INTO @tbl1(ActualValue) vALUES (100002)
INSERT INTO @tbl1(ActualValue) vALUES (100001)
INSERT INTO @tbl1(ActualValue) vALUES (200567)
INSERT INTO @tbl1(ActualValue) vALUES (345000)
INSERT INTO @tbl1(ActualValue) vALUES (345000)
INSERT INTO @tbl1(ActualValue) vALUES (456730)
INSERT INTO @tbl1(ActualValue) vALUES (234555)
INSERT INTO @tbl1(ActualValue) vALUES (456730)
INSERT INTO @tbl1(ActualValue) vALUES (112233)
INSERT INTO @tbl1(ActualValue) vALUES (112233)
INSERT INTO @tbl1(ActualValue) vALUES (443322)
INSERT INTO @tbl1(ActualValue) vALUES (334455)
INSERT INTO @tbl1(ActualValue) vALUES (112233)
INSERT INTO @tbl1(ActualValue) vALUES (443322)
INSERT INTO @tbl1(ActualValue) vALUES (112233)
INSERT INTO @tbl1(ActualValue) vALUES (334455)
INSERT INTO @tbl (ActualValue) SELECT ActualValue FROM @tbl1 ORDER BY ActualValue
DECLARE @RowId VARCHAR(20)
DECLARE @UpdatedValue INT
UPDATE Source
SET @UpdatedValue = (CASE
WHEN @RowId = ISNULL(Source.ActualValue,0) THEN ISNULL(@UpdatedValue,0)+1
ELSE ISNULL(Source.UpdatedValue,0)
END),
Source.UpdatedValue = ActualValue+'-'+REPLICATE('0',3-LEN(LTRIM(RTRIM(@UpdatedValue))))+CAST(@UpdatedValue AS VARCHAR(10)),
@RowId = ISNULL(Source.ActualValue,0)
FROM @tbl AS Source
SELECT * FROM @tbl
Ram
August 21, 2006 at 9:16 pm
Nicely done, Ram. The only problem is that the first sequence number comes out as -000 instead of -001 as the original requestor posted. However, that's an easy fix because of the good way you wrote the code. Here's the fix and a couple of shortcuts...
DECLARE @RowId VARCHAR(20)
DECLARE @UpdatedValue INT
SET @RowID = -1
SET @UpdatedValue=-1
UPDATE Source
SET @UpdatedValue = CASE
WHEN @RowId = Source.ActualValue
THEN @UpdatedValue+1
ELSE 1
END,
Source.UpdatedValue = ActualValue+'-'+REPLACE(STR(@UpdatedValue,3),' ','0'),
@RowId = Source.ActualValue
FROM @tbl AS Source
--Jeff Moden
Change is inevitable... Change for the better is not.
August 22, 2006 at 4:10 am
And one more way to do that - taking advantage of IDENTITY column (I'm using part of Ram's code, so that you can compare the differences):
/*prepare tables*/
DECLARE @tbl1 TABLE (ActualValue VARCHAR(30))
DECLARE @tbl TABLE
(rownr int IDENTITY,
ActualValue VARCHAR(30),
UpdatedValue VARCHAR(20))
/*insert test data*/
INSERT INTO @tbl1(ActualValue) vALUES (100001)
INSERT INTO @tbl1(ActualValue) vALUES (100001)
INSERT INTO @tbl1(ActualValue) vALUES (100048)
INSERT INTO @tbl1(ActualValue) vALUES (100001)
INSERT INTO @tbl1(ActualValue) vALUES (100002)
INSERT INTO @tbl1(ActualValue) vALUES (100001)
INSERT INTO @tbl1(ActualValue) vALUES (200567)
INSERT INTO @tbl1(ActualValue) vALUES (345000)
INSERT INTO @tbl1(ActualValue) vALUES (345000)
INSERT INTO @tbl1(ActualValue) vALUES (456730)
INSERT INTO @tbl1(ActualValue) vALUES (234555)
INSERT INTO @tbl1(ActualValue) vALUES (456730)
INSERT INTO @tbl1(ActualValue) vALUES (112233)
INSERT INTO @tbl1(ActualValue) vALUES (112233)
INSERT INTO @tbl1(ActualValue) vALUES (443322)
INSERT INTO @tbl1(ActualValue) vALUES (334455)
INSERT INTO @tbl1(ActualValue) vALUES (112233)
INSERT INTO @tbl1(ActualValue) vALUES (443322)
INSERT INTO @tbl1(ActualValue) vALUES (112233)
INSERT INTO @tbl1(ActualValue) vALUES (334455)
/*insert ordered data into intermediary table*/
INSERT INTO @tbl (ActualValue) SELECT ActualValue FROM @tbl1 ORDER BY ActualValue
/*calculate results in intermediary table - this is the actual work*/
UPDATE Source
SET Source.UpdatedValue = Source.ActualValue
+ '-'
+ RIGHT('000'+ CAST(Source.rownr-firstrow.min_rownr+1 AS VARCHAR(10)),3)
FROM @tbl AS Source
/*derived table "firstrow" finds lowest row number for each ActualValue*/
JOIN (SELECT t.ActualValue, MIN(t.rownr) as min_rownr
FROM @tbl t GROUP BY t.ActualValue) AS firstrow
ON firstrow.ActualValue = source.ActualValue
/*display results to check*/
SELECT * FROM @tbl
After you have checked, that the results are what you need, you can update your base table. Since you didn't specify anything about your table, I won't go into that part. I hope the idea is clear... you number the rows using identity column, and since they were ordered, you can easily calculate what to append to value in each row by taking actual row number and subtracting smallest row number for the same ActualValue ( + 1 if you don't want to start at 0).
August 23, 2006 at 2:02 am
Another way of doing it, without loops or identity.
It does however need a numbers table.
This is basically a technique that Itzik wrote about in SQL Server Mag June 2005 - 'Assigning Row Numbers for Non-Unique Rows'. That article explains in detail how it works.
Borrowing the #temp1 table from previous post in the thread:
create table #test1 (accno varchar(50))
go
insert #test1 values (100001)
insert #test1 values (100001)
insert #test1 values (100048)
insert #test1 values (100001)
insert #test1 values (100002)
insert #test1 values (100001)
insert #test1 values (200567)
insert #test1 values (345000)
insert #test1 values (345000)
insert #test1 values (456730)
insert #test1 values (234555)
insert #test1 values (456730)
insert #test1 values (112233)
insert #test1 values (112233)
insert #test1 values (443322)
insert #test1 values (334455)
insert #test1 values (112233)
insert #test1 values (443322)
insert #test1 values (112233)
insert #test1 values (334455)
go
This is the query, 1st column is just the original accno, the 2nd is the enumerated and concatenated endresult.
select z.accno, z.accno + right('00' + cast(n.n as varchar(3)), 3)
from ( select y.accno,
count(*) as dupes,
(select count(*) from #test1 x where x.accno < y.accno ) as smaller
from #test1 y
group by accno
) z
join nums n
on n.n <= z.dupes
/Kenneth
August 23, 2006 at 6:54 pm
Hmmmm... that just made me realize that we're all forgetting something.... none of the SELECTs, so far, expose the Primary Key.
--Jeff Moden
Change is inevitable... Change for the better is not.
Viewing 9 posts - 1 through 8 (of 8 total)
You must be logged in to reply to this topic. Login to reply