Store procedure process actual and next row

lunedì 26 marzo 2007 - 14.33

aleplgr Profilo | Junior Member

Hi!, I need a stored procedure that calculates differences between the current row and the next row of a given table
The initial table is this, 3 columns: a CientID and 2 dates,
and it's ordered by ClientId and Date2
ClienID Date2 Date1
1 a b
1 c d
1 e f

the first row is ClientID= 1, Date2 = a and Date1=b
the next row is ClientID=1, Date2=c and Date1=d
the next row is ClientID=1, Date2=e and Date1=f
the first difference is c-b, if this difference is >30 return (1,b) else calculate the second difference: e-d, if this difference is >30 return (1,c)
if there's no difference >30 return the last Date1 for the ClientID
and continue with the next ClientID to do the same..
the result should be a 2 columns table (ClientID, Date1)

The main problem I think is to process the actual and next row to calculate that differences

Here's an example with dates:
ClientID Date2 Date1
1 10.01.2007 01.01.2007
1 20.01.2007 13.01.2007
1 25.02.2007 01.02.2007
1 15.03.2007 27.02.2007
2 10.01.2007 01.01.2007
2 20.01.2007 13.01.2007
2 05.02.2007 01.02.2007

with the following result set:

ClientID Date1
1 13.01.2007 //25.02.2007- 13.01.2007 is the first > 30 days
2 01.02.2007 //No records with > 30 days difference

Please help, a high level pseudocode of the procedure will be excellent

bluland Profilo | Guru

HI,
Id like to know if u can add another column to your table, for example a column for Id like follow example:

mytable

id ClientId Date2 Date1


then?

regards
--------------------
Vincenzo PESANTE

aleplgr Profilo | Junior Member

Yes, I can add columns if that what needs to be done to solve it..

I made a mistake in the post, the first difference was ok:
the first difference is c-b, if this difference is >30 return (1,b)

but in the second difference I should have written (1,d) instead of (1,c) in the result table, this is ok now:
else calculate the second difference: e-d, if this difference is >30 return (1,d)

Because we must return (ClientID, Date1)

Sorry

bluland Profilo | Guru

So at the end you need to return all records (cliendid, date1) where the difference is >30 is right?
else if there isnt difference > 30 you dont return anything right?


--------------------
Vincenzo PESANTE

aleplgr Profilo | Junior Member


if there's no difference >30 for a ClientID then return the last Date1 for that ClientID

and for all the clients that have just one Date1 and one Date2 just return that ClientID and Date1

Thanks

bluland Profilo | Guru

ah ok so for example if I ve this values what itll be the result?

ID ClientId Date2 Date1
-------------------- -------------------- ------------------------------------------------------ ---------------
1 1 2007-01-10 2007-01-01
2 1 2007-01-20 2007-01-13
3 1 2007-01-25 2007-02-01
4 2 2007-01-10 2007-01-01
5 2 2007-02-20 2007-01-13
6 2 2007-02-13 2007-02-01


I'll give u a solution with Sql 2000
--------------------
Vincenzo PESANTE

aleplgr Profilo | Junior Member



ClientID Sec Date2 Date1
1 1 2007-01-10 2007-01-01
2 1 2007-01-20 2007-01-13
3 1 2007-01-25 2007-02-01
4 2 2007-01-10 2007-01-01
5 2 2007-02-20 2007-01-13
6 2 2007-02-13 2007-02-01


ClientID=1
the 1st dif is 2007-01-20 - 2007-01-01 <30
the 2nd dif is 2007-01-25 - 2007-01-13 <30
ret (1,2007-02-01)

ClientId=2
the 1st dif is 2007-02-20 - 2007-01-01 <30
the 2nd dif is 2007-02-13 - 2007-01-13 <= 30
ret(2,2007-02-01)

resulttotal
ClientID Date1
1 2007-02-01
2 2007-02-01

Don't worry about the specifics of SQL 2000 a high level pseudocode would be fine (I hope)
thanks

bluland Profilo | Guru

>
>
>ClientID Sec Date2 Date1
>1 1 2007-01-10 2007-01-01
>2 1 2007-01-20 2007-01-13
>3 1 2007-01-25 2007-02-01
>4 2 2007-01-10 2007-01-01
>5 2 2007-02-20 2007-01-13
>6 2 2007-02-13 2007-02-01
>
>
>ClientID=1
>the 1st dif is 2007-01-20 - 2007-01-01 <30
>the 2nd dif is 2007-01-25 - 2007-01-13 <30
>ret (1,2007-02-01)
>
>ClientId=2
>the 1st dif is 2007-02-20 - 2007-01-01 <30

but is > 30 ????
so??

>the 2nd dif is 2007-02-13 - 2007-01-13 <= 30
>ret(2,2007-02-01)

>resulttotal
>ClientID Date1
>1 2007-02-01
>2 2007-02-01

resulttotal
ClientID Date1
1 2007-02-01
2 2007-02-20

is right?
EDIT:

and if there's more then >30 for each clientid what u ve to return all or what??
--------------------
Vincenzo PESANTE

aleplgr Profilo | Junior Member

Ohh sorry made another mistake in the ClientID=2, the first difference is > 30, then return the Date1 that causes that difference:

>ClientId=2
>the 1st dif is 2007-02-20 - 2007-01-01 >30

return(2007-01-01), the Date1

resulttotal
ClientID Date1
1 2007-02-01
2 2007-01-01

bluland Profilo | Guru

yes but if there's more then >30 for each clientid what u ve to return all or what??
--------------------
Vincenzo PESANTE

aleplgr Profilo | Junior Member

If there's more than one > 30 I have to return the first one found, for each clientID

bluland Profilo | Guru

OK i give u in SQL 2000 all script

Ex. Table, some insert and Stored Procedure

Il codice sorgente non è stato renderizzato qui
perchè non c'è sufficiente spazio.
Clicca qui per visualizzarlo in una nuova finestra
that's all!

--------------------
Vincenzo PESANTE

aleplgr Profilo | Junior Member

GREAT!!!!! Thanks!!!
GRAZIE!!!!!!!!!!

bluland Profilo | Guru

>GREAT!!!!! Thanks!!!
>GRAZIE!!!!!!!!!!
Prego!
--------------------
Vincenzo PESANTE

aleplgr Profilo | Junior Member

I feel ashamed but I had to modify the procedure because it can be a clientid with just one row, so idmax=idmin and for those cases it does not work, I modified the procedure and added this lines right before the first cicle starts:

IF (IDMAX = IDMIN) THEN BEGIN SELECT DATE1 FROM MYTABLE WHERE ID =:IDMIN INTO :MYDATE; SELECT CLIENTID FROM MYTABLE WHERE ID =:IDMIN INTO :MYCLIENT; INSERT INTO FIN (CLIENTID,MYDATE) VALUES (:MYCLIENT,:MYDATE); END
Works fine but those clients who have just one row appear twice in the final file... so although I had the procedure almost done here for me I still can't make it work

bluland Profilo | Guru

This script check also if there 's only one row for some clientid:


SET QUOTED_IDENTIFIER ON GO SET ANSI_NULLS ON GO ALTER PROCEDURE sp_DIFFDATE AS DECLARE @maxclientid as decimal, @minclientid as decimal, @idmin as decimal, @idmax as decimal, @val1 as datetime, @val2 as datetime, @Days as decimal, @myclient as decimal, @mydate as datetime, @clientidmax as decimal, @verRow as integer -- Temp table create table #temp ( ID decimal(18, 0) IDENTITY (1, 1) NOT FOR REPLICATION NOT NULL , Clientid decimal, myDate datetime, flag bit -- If 1 means that difference is >30 ) -- final table create table #fin ( Clientid decimal, myDate datetime ) --find first and last clientid set @maxclientid = (SELECT MAX(clientid) FROM MYTABLE) set @mINclientid = (SELECT MIN(clientid) FROM MYTABLE) WHILE @maxclientid + 1 > @mINclientid BEGIN --verify if there's only one row SET @verRow =(SELECT COUNT(*) FROM MYtable WHERE clientid = @mINclientid) -- Row = 1 IF (@verRow <= 1) BEGIN set @mydate = (SELECT date1 from mytable where clientid = @mINclientid) INSERT INTO #temp(Clientid,myDate,flag)VALUES (@mINclientid,@mydate,0) select * from #temp INSERT INTO #fin(Clientid,myDate)VALUES (@mINclientid,@mydate) set @mINclientid = @mINclientid + 1 END ELSE BEGIN -- select the range of id for each client start from first clientid set @idmax = (SELECT MAX(id) FROM MYTABLE WHERE clientid = @mINclientid ) set @idmin = (SELECT MIN(id) FROM MYTABLE WHERE clientid = @minclientid ) SELECT MAX(id) FROM MYTABLE WHERE clientid = @mINclientid SELECT MIN(id) FROM MYTABLE WHERE clientid = @minclientid --analyze each client id client start from first clientid -- first cicle WHILE @idmax > @idmin BEGIN -- Take the values of two rows set @val1 = (SELECT Date1 FROM MYtable WHERE ID = @idmin ) set @val2 = (SELECT Date2 FROM MYtable WHERE ID = @idmin + 1 ) -- that's next row -- Make my difference set @Days = (SELECT DATEDIFF(DAY,@val1, @val2)) -- get clientid and date set @myclient = (SELECT clientid from mytable where id = @idmin) IF (@DAYS > 30) BEGIN set @mydate = (SELECT date1 from mytable where id = @idmin) INSERT INTO #temp(Clientid,myDate,flag)VALUES (@myclient,@mydate,1) END ELSE BEGIN set @mydate = (SELECT date1 from mytable where id = @idmin + 1) INSERT INTO #temp(Clientid,myDate,flag)VALUES (@myclient,@mydate,0) END -- next id for current clientid set @idmin = @idmin + 1 END --end first cicle -- Check for this clientid if exist flag 1 IF ((SELECT COUNT(*) FROM #temp WHERE flag = 1) > 0 ) BEGIN -- select first clientid and date set @myclient = (SELECT clientid FROM #temp WHERE id=(SELECT MIN(ID) FROM #temp WHERE flag = 1)) set @mydate = (SELECT myDate FROM #temp WHERE id=(SELECT MIN(ID) FROM #temp WHERE flag = 1)) END ELSE BEGIN -- no >30 return the last Date1 for that ClientID set @myclient = (SELECT clientid FROM #temp WHERE id=(SELECT MAX(ID) FROM #temp WHERE flag = 0)) set @mydate = (SELECT myDate FROM #temp WHERE id=(SELECT MAX(ID) FROM #temp WHERE flag = 0)) END -- put result into final table INSERT INTO #fin(Clientid,myDate)VALUES (@myclient,@mydate) -- clean tmp table DELETE from #temp set @mINclientid = @mINclientid + 1 END END -- select result select DISTINCT * from #fin GO SET QUOTED_IDENTIFIER OFF GO SET ANSI_NULLS ON GO

do try and tell me about that!

CIao!
--------------------
Vincenzo PESANTE

aleplgr Profilo | Junior Member

Thanks, now works for the one row CLIENTIDs...

But now I found that It does not work for a case like CLIENTID = 3 where the first difference = 37 and the second difference is 66, it shows in the FIN table the second date (04/03/1998) and it should show the first one (06/12/1997)
I debugged it and it saves in the FIN table the correct date (06/12/1997) and then does not save to the FIN table anymore when I debug it, but when I run the procedure and check the FIN table appears the wrong date (04/03/1998)

I also run it with a test table which has only the CLIENTID = 3 and it works fine, it saves to the FIN table the right date (06/12/1997)

CLIENTID DATE2 DATE1 ID
1,000000 10/01/2007 0:00 01/01/2007 0:00 2,000000
1,000000 20/01/2007 0:00 13/01/2007 0:00 3,000000
1,000000 25/01/2007 0:00 01/02/2007 0:00 4,000000
2,000000 10/01/2007 0:00 01/01/2007 0:00 5,000000
2,000000 20/02/2007 0:00 13/01/2007 0:00 6,000000
2,000000 05/02/2007 0:00 03/02/2007 0:00 7,000000
3,000000 24/11/1997 0:00 06/12/1997 0:00 8,000000
3,000000 12/01/1998 0:00 04/03/1998 0:00 9,000000
3,000000 09/05/1998 0:00 20/11/1998 0:00 10,000000

I inserted all the rows in another new table because maybe it was some problem with the old table but I got the same wrong result for CLIENTID=3, it's strange, I don't know what's happening...

It would help me so much if you add CLIENTID=3 to your table and run it in SQL2000, maybe it's some problem with my tables...Sorry for this neverending post

bluland Profilo | Guru

thats here:

plaease next time do write the insert statment in sql ansi

Il codice sorgente non è stato renderizzato qui
perchè non c'è sufficiente spazio.
Clicca qui per visualizzarlo in una nuova finestra
so its right?

saluti and good easter
--------------------
Vincenzo PESANTE

aleplgr Profilo | Junior Member

Thanks!! Yes, it's alright.. so the problem is in my initial table.. so far I was inserting data without a generator: just by hand..
I think that's why it's not working for my data...

I'm trying to create a generator for the table created from a SELECT in order, but in InterBase I need to do something like this:
insert all records into the table
then run an SP which does something like this

for select cola, colb, colc from test into :a, :b, :c order by cola, colb, colc
do
begin
update test set cold = genid(my_gen, 1) where cola = :a and
colb = :b and colc = :c;
end

I didn't make it work yet but I think I will..
I hope that when I could solve this, it will be finished, I'll let you know
Partecipa anche tu! Registrati!
Hai bisogno di aiuto ?
Perchè non ti registri subito?

Dopo esserti registrato potrai chiedere
aiuto sul nostro Forum oppure aiutare gli altri

Consulta le Stanze disponibili.

Registrati ora !
Copyright © dotNetHell.it 2002-2024
Running on Windows Server 2008 R2 Standard, SQL Server 2012 & ASP.NET 3.5