Please start any new threads on our new
site at https://forums.sqlteam.com. We've got lots of great SQL Server
experts to answer whatever question you can come up with.
Author |
Topic |
marcodelphi
Starting Member
4 Posts |
Posted - 2010-07-01 : 15:55:59
|
Hello Guys, I'm trying to modify a history table, where given a new entry, the table is recreated (only for records with the same ID). Columns DataAtivacao DataDesativacao and all records of the same ID will suffer a "realignment" of their dates. For example, the field DataDesativacao of the previous record should be changed to "DataAtivacao of the current record - 1". Below is the schema of the database. Than, an example of input / output and also the expected result of what has already tried to solve the problem. Table Schema: CREATE TABLE [dbo]. [HistoricoInventario] ( [HistoricoID] bigint IDENTITY (1, 1) NOT NULL, [DispositivoID] int NOT NULL, [DataAtivacao] datetime NOT NULL, [DataDesativacao] datetime CONSTRAINT [DF__Historico__DataD__66603565] DEFAULT '3000 / 01/01 'NULL, CONSTRAINT [HistoricoInventario_pk] PRIMARY KEY CLUSTERED ([HistoricoID] [DispositivoID] [DataAtivacao]) CONSTRAINT [HistoricoInventario_uq] UNIQUE ([DispositivoID] [DataAtivacao]) ) ON [PRIMARY] GO The problem is that I have to keep up the history, I mean, the dates of DataAtivacao and DataDesativacao. Until now, there is no problem, unless I've got to keep the dates "making sense", I mean, when I change the date of DataAtivacao / DataDesativacao of a record, I have to recreate all the other historical containing the same DispositivoID, ie:The DateFormat is: dd/mm/yyyyI have the following history, which DispositivoID = 1: ID DispositivoID DataAtivacao DataDesativacao1 1 01/01/2010 05/01/2010 2 1 06/01/2010 20/01/2010 3 1 21/01/2010 22/01/2010 If DataAtivacao record with ID = 2, is changed to 08/01/2010 and DataDesativacao to 22/01/2010, the result of this change should be the following: ID DispositivoID DataAtivacao DataDesativacao1 1 01/01/2010 07/01/2010 2 1 08/01/2010 22/01/2010 3 1 23/01/2010 23/01/2010 I have come across with the following, but no satisfy solution, which consists of trigger that changes the previous associated record. This procedure will change only the first previous record of a given DispositivoID:CREATE PROCEDURE dbo.GetLastDataDesativacao @DispositivoID int, @HistoricoIDAnterior bigint OUTPUTASBEGIN SET NOCOUNT ON DECLARE @HistoricoIDAtual BIGINT DECLARE @DataNew datetime, @DataOld datetime SELECT @HistoricoIDAtual = MAX(HI.HistoricoID) FROM Funcoes.dbo.HistoricoInventario HI WHERE HI.DispositivoID=@DispositivoID SELECT TOP 1 @HistoricoIDAnterior = HistoricoID, @DataOld = b.DataDesativacao, @DataNew = (SELECT TOP 1 DataDesativacao FROM Funcoes.dbo.HistoricoInventario a WITH(NOLOCK) WHERE a.DispositivoID = b.DispositivoID AND a.DataDesativacao < b.DataDesativacao ) FROM Funcoes.dbo.HistoricoInventario b WITH(NOLOCK) WHERE b.DispositivoID = @DispositivoID AND b.HistoricoID <= (SELECT MAX(HistoricoID) FROM Funcoes.dbo.HistoricoInventario WHERE DispositivoID = @DispositivoID) ORDER BY b.DataDesativacao DESC RETURN @HistoricoIDAnteriorENDCREATE TRIGGER [dbo].[HistoricoInventario_tri] ON [dbo].[HistoricoInventario]WITH EXECUTE AS CALLERINSTEAD OF INSERTASBEGIN-- Ao inves de inserir, faça o seguinte: DECLARE @id int, @DataAtivacao datetime, @DataDesativacao datetime, @UltimaDesativacao datetime, @HistoricoIDAtual bigint, @HistoricoIDAnterior bigint, @DebugData nvarchar(200) SELECT @id = I.DispositivoID, @DataAtivacao = I.DataAtivacao, @DataDesativacao = I.DataDesativacao FROM INSERTED I --Pega o código do historico --Se ja existe um historico com o mesmo dispositivo, --entao altera a data de desativacao do ultimo registro --para 1 dia antes da data de ativacao do registro sendo inserido IF EXISTS (SELECT HC.DispositivoID FROM Funcoes.dbo.HistoricoInventario HC WHERE HC.DispositivoID = @id) BEGIN -- Atualiza o registro anterior -- Altera a data de desativacao do registro anterior EXEC Funcoes.dbo.GetLastDataDesativacao @id, @HistoricoIDAnterior OUTPUT UPDATE Funcoes.dbo.HistoricoInventario SET DataDesativacao = DATEADD(day,-1,@DataAtivacao) WHERE DispositivoID = @id AND HistoricoID = @HistoricoIDAnterior -- Insere o novo registro IF @DataDesativacao IS NOT NULL INSERT INTO Funcoes.dbo.HistoricoInventario(DispositivoID,DataAtivacao,DataDesativacao) VALUES (@id,@DataAtivacao,@DataDesativacao) ELSE INSERT INTO Funcoes.dbo.HistoricoInventario(DispositivoID,DataAtivacao) VALUES (@id,@DataAtivacao) END ELSE IF @DataDesativacao IS NOT NULL INSERT INTO Funcoes.dbo.HistoricoInventario(DispositivoID,DataAtivacao,DataDesativacao) VALUES (@id,@DataAtivacao,@DataDesativacao ) ELSE INSERT INTO Funcoes.dbo.HistoricoInventario(DispositivoID,DataAtivacao) VALUES (@id,@DataAtivacao) RETURNENDGO This procedure works only for the first previous record, which does not solve the problem. The table must be rebuilt according to the input. I hope I have been happy to expose the problem. Any help will be appreciated. Thank you, Marco André |
|
yosiasz
Master Smack Fu Yak Hacker
1635 Posts |
Posted - 2010-07-01 : 16:24:29
|
1. can we assume you want the changes to cascade down (if there are any records downstream) and cascade up (if there are any records upstream)2. Can we also assume both DataAtivacao and DataDesativacao can change and that triggers the changes described in #1?3. can DataAtivacao change and not DataDesativacao (vise versa) or they change together? what triggers the change, UI or another process?<><><><><><><><><><><><><><><><><><><><><><><><><>If you don't have the passion to help people, you have no passion |
 |
|
marcodelphi
Starting Member
4 Posts |
Posted - 2010-07-01 : 16:39:48
|
Hi Yosiasz, thanks for your reply.Lets continue...1.Correct. All the changes are cascaded down and upstream2.Correct.3.Both can change, but not allways at the same time. Changes can be made only in one field or in both fields.The change is made by an UI. |
 |
|
marcodelphi
Starting Member
4 Posts |
Posted - 2010-07-01 : 22:37:43
|
quote: Originally posted by marcodelphi Hi Yosiasz, thanks for your reply.Lets continue...1.Correct. All the changes are cascaded down and upstream2.Correct.3.Both can change, but not allways at the same time. Changes can be made only in one field or in both fields.The change is made by an UI.
I have more info about the issue:Actually none of the rows should be deleted. If I insert a new record, it doesnt matter the date, all the related dates, from the specified DispositivoID should be realigned. That is also true if I update a record.If I change any of the 2 fields(DataAtivacao/DataDesativacao-StartDate/EndDate) in any record, all related records(from specified ID) should be realigned.There are no limit to the changes. If there are 1000 records above or below a date, than all the records should be realigned.All the changes, including new records added, should trigger a procedure that will process all related records downstream and upstream. For instance, taking your example above. Lets suppose a user runs the following queries against the table:INSERT INTO HistoricoInventario(1,'13/01/2010','17/01/2010');INSERT INTO HistoricoInventario(1,'18/01/2010','27/01/2010');UPDATE HistoricoInventario SET StartDate='07/01/2010', EndDate='10/01/2010'WHERE ID=2; Here is a list of each statement with the their respective resultset:Original state:ID DispositivoID StartDate EndDate1 1 01/01/2010 05/01/2010 2 1 06/01/2010 15/01/20103 1 16/01/2010 20/01/20104 1 21/01/2010 22/01/2010INSERT INTO HistoricoInventario(1,'13/01/2010','17/01/2010')1 1 01/01/2010 05/01/2010 2 1 06/01/2010 14/01/2010*5 1 13/01/2010 17/01/2010 -- new record(find the gap, and realing all other records)3 1 18/01/2010 20/01/20104 1 21/01/2010 22/01/2010INSERT INTO HistoricoInventario(1,'18/01/2010','27/01/2010')1 1 01/01/2010 05/01/2010 2 1 06/01/2010 13/01/20105 1 14/01/2010 15/01/20103 1 16/01/2010 17/01/2010*6 1 18/01/2010 27/01/2010 -- new record(find the gap, and realing all other records)4 1 28/01/2010 28/01/2010UPDATE HistoricoInventario SET StartDate='07/01/2010', EndDate='10/01/2010' WHERE ID=21 1 01/01/2010 06/01/2010 -- step2,previous record changed(EndDate=StartDate from current record(2) minus 1*2 1 07/01/2010 10/01/2010 -- step1,record updated5 1 11/01/2010 15/01/2010 -- step3,next record changed(StartDate=DataDesativacao current record(2) plus 13 1 16/01/2010 17/01/2010 -- step4,doesnt need to make change, because all the next and previous dates are aligned.6 1 18/01/2010 27/01/2010 -- step5,same as step44 1 28/01/2010 28/01/2010 -- step6,same as step4 I hope you can understand now. If you still have any doubt, please, let me know.Thank you very much for your help!Marco André |
 |
|
yosiasz
Master Smack Fu Yak Hacker
1635 Posts |
Posted - 2010-07-07 : 11:26:08
|
the only way I can think of doing this is with a sql cursor you loop through. DECLARE cursor_name CURSOR and all. This cursor will be built using the DispositivoID in the WHERE clause excluding the record that changed. (assuming user can change only one record at a time. Is that correct?) SORTED BY DataAtivacao. Then for each row grab last value and update the next record type of thing sounds chungy but might work.<><><><><><><><><><><><><><><><><><><><><><><><><>If you don't have the passion to help people, you have no passion |
 |
|
|
|
|
|
|