May 20, 2003 at 4:13 pm
Hi, Gurus.
I have a q for U.
I have been fighting with this for a while.
So I need some help.
Here is some data..
-----------------------------
ID Code SomethingIWant
1 A A01
2 A A02
4 B B01
23 C C01
34 C C02
25 C C03
89 D D01
-------------------------------
ID column is random but unique.
SomethingIWant column is the one I want to generate.
What I have been doing is using a cursor(Fetch Next). Check to next Code and if that code is the same as before, I want to add "01" at the end. Next one goes "02", if not start with "01"..However that doesnt quite work for me right now..
Any other idea?
Thx in advance.
Jay
May 20, 2003 at 4:56 pm
Create Table Test(id int, Code char(1), SomethingIWant Varchar(10))
GO
Insert test values(1,'A','')
Insert test values(2,'A','')
Insert test values(4,'B','')
Insert test values(23,'C','')
Insert test values(34,'C','')
Insert test values(25,'C','')
Insert test values(89,'D','')
GO
Update t1
Set SomethingIWant=
Case When IsNull((Select count(*)
from test as t2
where t2.[id]<t1.[id] And
t2.code=t1.code),0)<=0 Then t1.Code+'01'
Else t1.Code+Replace(Right(' '+Cast((Select count(*)
from test as t3
where t3.[id]<t1.[id] And
t3.code=t1.code)+1 as VarChar(2)),2),' ','0') End
from Test as t1
GO
Select * from Test Order by Code,[id]
go
Drop table test
go
May 20, 2003 at 5:00 pm
Here's an example that you can paste into SQL query analyzer. I use this all the time, and have gotten away from the traditional cursors. Haven't ever used it on a really big recordset, I bet it would be really slow!
--Create a temp table with some test values...
CREATE TABLE #test (ID INT, letr varchar(1))
INSERT INTO #test (ID, letr) VALUES(1, 'A' )
INSERT INTO #test (ID, letr) VALUES(2, 'A' )
INSERT INTO #test (ID, letr) VALUES(4, 'B' )
INSERT INTO #test (ID, letr) VALUES(23, 'C' )
INSERT INTO #test (ID, letr) VALUES(24, 'C' )
INSERT INTO #test (ID, letr) VALUES(25, 'C' )
INSERT INTO #test (ID, letr) VALUES(89, 'D' )
--Create another table with the new column, copy data to it...
--Here is where you could create another field such as ID2 INT IDENTITY to
--base the 'looping' on.
CREATE TABLE #results (ID INT, letr Varchar(1), siw Varchar(3))
INSERT INTO #results (ID, letr)
SELECT * FROM #test
--Look at data before processing
SELECT * FROM #results
--Set up variables
DECLARE @ctr INT
DECLARE @valctr INT
DECLARE @max INT
DECLARE @siw VarChar(3)
DECLARE @curletr Varchar(1)
DECLARE @prvletr Varchar(1)
SET @ctr = (SELECT MIN(ID) FROM #results)
SET @max = (SELECT MAX(ID) FROM #results)
SET @prvletr = ''
--Go row by row. Note that if your recordset doesn't have
WHILE @ctr <= @MAX
BEGIN
SET @curletr = (SELECT letr FROM #results WHERE ID = @ctr)
IF @curletr IS NOT NULL
BEGIN
IF @curletr = @prvletr
SET @valctr = @valctr + 1
ELSE
SET @valctr = 1
SET @siw = @curletr + CASE When LEN(@valctr) = 1 then '0' ELSE '' END + CAST(@valctr AS VARCHAR(2))
UPDATE #results SET siw = @siw WHERE ID = @ctr
SET @prvletr = @curletr
END
SET @ctr = @ctr + 1
END
--Look at the results:
SELECT * FROM #results
--Cleanup
DROP TABLE #results
If there are lots of gaps in your ID field, or it's not numeric, you can create another field as a counter such as ID2 INT IDENTITY, and base the looping on that field.
Hope it helps!
May 21, 2003 at 8:51 am
I'm guessing that Len's (5409045121009) solution would be better than mine since it's a set-based solution wheras mine uses a row by row approach. It would be interesting to see how these would compare on a really large recordset...
May 21, 2003 at 9:42 am
One more solution using derived table
update t1
set somethingiwant = t2.somethingiwant
from test as t1
join(SELECTid,
code+CAST((select count(*)
from test b
where a.code = b.code
and a.id >=b.id)
as varchar(10)) as somethingiwant
from test a
)as t2
on t1.id = t2.id
May 21, 2003 at 9:44 am
BTW, I was using 5409045121009 table structure. Also I didnt put in the leading zeros but that would be easy enough if you need it.
May 21, 2003 at 3:39 pm
Try to improve the update a bit.
Update t1
Set SomethingIWant=
Case When Exists(Select '1' from test as t2 where t2.[id]<t1.[id] And t2.code=t1.code) Then
t1.Code+Right('0'+Cast((Select count(*) from test as t3 where t3.[id]<t1.[id] And t3.code=t1.code)+1 as VarChar(2)),2)
Else t1.Code+'01' End
from Test as t1
May 22, 2003 at 9:39 am
Hi, Guys..
U guys are really GURUS.....
I have huge data set.. I will test both ways and I will let U know..
And I have a q for 5409045121009.
Would U explain this logic a little bit..
Select '1' from test as t2 where t2.[id]<t1.[id] And t2.code=t1.code
And I have a q for GregLyon.
Would U explain this logic a little bit..
SET @siw = @curletr + CASE When LEN(@valctr) = 1 then '0' ELSE '' END + CAST(@valctr AS VARCHAR(2))
Thx
Jay
May 22, 2003 at 2:29 pm
Rheejay, if one look at the statement with the Exists in mind, I am trying to determine 'are there any previous entries for the same code'. If not then this is the start of a 'run' else go and count how many are before this one.
Select '1' from test as t2 where t2.[id]<t1.[id] And t2.code=t1.code
May 23, 2003 at 8:26 am
Hi Rheejay,
SET @siw = @curletr + CASE When LEN(@valctr) = 1 then '0' ELSE '' END + CAST(@valctr AS VARCHAR(2))
This line of SQL starts with your letter and concatenates a number to it. The CASE statement just adds a leading 0 if the @valctr variable is between 1 and 9, so you end up with A01, A02, A03 instead of A1, A2, A3. The CAST part makes sure that SQL doesn't try to treat the value as a number and attempt to do addition instead of concatenation.
May 23, 2003 at 8:39 am
Thx All..
This makes whole lot sense
Jay
May 23, 2003 at 9:27 am
Oh..Man..I forgot something to post..
I have 4500 records to test the both of ways.
-GregLyon's script ran for 40 mins but did not finish to pull.
-5409045121009's script ran less than a 2 seconds to update column.
I think, for the performance purpose, 5409045121009's script is faster.
However GregLyon's script gave me lots of thoughts regarding cursor so I think I can apply this logic to other scripts.
Thx for all..
Jay
May 24, 2003 at 3:46 pm
CREATE TABLE #test (ID INT, letr varchar(1))
INSERT INTO #test (ID, letr) VALUES(1, 'A' )
INSERT INTO #test (ID, letr) VALUES(2, 'A' )
INSERT INTO #test (ID, letr) VALUES(4, 'B' )
INSERT INTO #test (ID, letr) VALUES(23, 'C' )
INSERT INTO #test (ID, letr) VALUES(24, 'C' )
INSERT INTO #test (ID, letr) VALUES(25, 'C' )
INSERT INTO #test (ID, letr) VALUES(89, 'D' )
-- or try this
select a.ID, max(a.letr) letr, max(a.letr)+ substring(convert(char, count(*)+100),2,2)SomethingUWant
from #test a, #test b
where b.ID<=a.id and b.letr=a.letr
group by a.ID
Viewing 13 posts - 1 through 12 (of 12 total)
You must be logged in to reply to this topic. Login to reply