Jon_Raymond
asked on
Trigger update to aggregated table
I'm importing 30 fields of data to tableA every hour or so. One of the fields is the date and time the data was logged. I want to also archive this data to another table, but change the date and time to a date only, i.e. all times are converted to 0 and I keep the date as the value. But, I have to sum all the other fields to do this. So, I tried a trigger on Table1 to aggregate the INSERTED table data into timeless date records and then insert that data to table2 the aggregated archive table. The problem is that a date may already exist in table2. So, I have to add that date's data as well. I can do this below, but I don't know how to remove the old records from table2 that I need to replace. Any ideas? I assume this must be a standard process that is often needed.
INSERT dbo.Table2
(
StaffID,
Archivetime,
State,
Amount
)
SELECT
i.StaffID,
CONVERT(datetime,CONVERT(i nt,i.archi vetime)) Archivetime,
i.State,
SUM(ISNULL(i.Amount,0)) + SUM(ISNULL(a.Amount,0)) As Amount
FROM INSERTED i
LEFT OUTER JOIN dbo.Table2 a ON i.StaffID=a.StaffID
AND i.State= a.State
AND CONVERT(datetime,CONVERT(i nt,i.archi vetime))=a .ArchiveTi me
Group By i.StaffID, CONVERT(datetime,CONVERT(i nt,i.archi vetime)), i.State
DELETE a
FROM dbo.Table2 a
JOIN INSERTED s ON a.StaffID=s.StaffID
AND a.State = s.State
WHERE
a.ArchiveTime = CONVERT(datetime,CONVERT(i nt,a.archi vetime))
AND a.Amount <a.Amount-s.Amount
INSERT dbo.Table2
(
StaffID,
Archivetime,
State,
Amount
)
SELECT
i.StaffID,
CONVERT(datetime,CONVERT(i
i.State,
SUM(ISNULL(i.Amount,0)) + SUM(ISNULL(a.Amount,0)) As Amount
FROM INSERTED i
LEFT OUTER JOIN dbo.Table2 a ON i.StaffID=a.StaffID
AND i.State= a.State
AND CONVERT(datetime,CONVERT(i
Group By i.StaffID, CONVERT(datetime,CONVERT(i
DELETE a
FROM dbo.Table2 a
JOIN INSERTED s ON a.StaffID=s.StaffID
AND a.State = s.State
WHERE
a.ArchiveTime = CONVERT(datetime,CONVERT(i
AND a.Amount <a.Amount-s.Amount
ASKER
Adjusted points to 100
ASKER CERTIFIED SOLUTION
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
ASKER
Returns Error 260: Disallowed implicit conversion from datatype datetime to datatype int table 'table2' Column 'StaffID' use CONVERT function to run this query.
But, I'm still playing with it
But, I'm still playing with it
ASKER
Excellent, Thank you.
ASKER
Here are the changes I made:
CREATE TRIGGER dbo.trgUpdateAgg ON [tmData]
for insert
as
begin
if (select count(*)
from tmDataAgg
join inserted
on cast(convert(int,tmDataAgg .Archiveti me)as datetime)=cast(convert(int ,inserted. Archivetim e)as datetime)
AND tmDataAgg.StaffID=inserted .StaffID
AND tmDataAgg.State=inserted.S tate)
=0
begin
insert tmDataAgg
(
ArchiveTime,
StaffID,
State,
Amount
)
select
convert(DateTime,convert(i nt,inserte d.Archivet ime),101) Archivetime,
inserted.StaffID,
inserted.State,
isnull(inserted.Amount,0) Amount
from inserted
end
else
begin
update tmDataAgg
set tmDataAgg.Amount=tmDataAgg .Amount+is null(inser ted.Amount ,0)
from inserted
where tmDataAgg.StaffID
=inserted.StaffID and
cast(convert(int,tmDataAgg .Archiveti me)as datetime)
=cast(convert(int,inserted .Archiveti me)as datetime) and
tmDataAgg.State
=inserted.State
end
end
CREATE TRIGGER dbo.trgUpdateAgg ON [tmData]
for insert
as
begin
if (select count(*)
from tmDataAgg
join inserted
on cast(convert(int,tmDataAgg
AND tmDataAgg.StaffID=inserted
AND tmDataAgg.State=inserted.S
=0
begin
insert tmDataAgg
(
ArchiveTime,
StaffID,
State,
Amount
)
select
convert(DateTime,convert(i
inserted.StaffID,
inserted.State,
isnull(inserted.Amount,0) Amount
from inserted
end
else
begin
update tmDataAgg
set tmDataAgg.Amount=tmDataAgg
from inserted
where tmDataAgg.StaffID
=inserted.StaffID and
cast(convert(int,tmDataAgg
=cast(convert(int,inserted
tmDataAgg.State
=inserted.State
end
end
ASKER
qpbuenrostro, I reacted too quickly. I thought you answer was the solution. But, it only works under certain conditions. If I have multiple records in Table1 (or rather the INSERT table) with the same date (not time) then I need to add them up into one record to insert or update to table2. This doesn't happen. It just adds the last record.
I have to be able to add all records from table1 (or the INSERT table) that have the same dates and also add then to any existing record in table2 with that same date, or just insert them to table2 if no existing record matches the date.
You can't use aggregation with an UPDATE so I thought it would be necessary to delete the records and replace them with aggregated records.
I have to be able to add all records from table1 (or the INSERT table) that have the same dates and also add then to any existing record in table2 with that same date, or just insert them to table2 if no existing record matches the date.
You can't use aggregation with an UPDATE so I thought it would be necessary to delete the records and replace them with aggregated records.
Jon_Raymond,
Be careful when removing time portion from datetime datatype. Check next situation:
set nocount on
select 'Today'=getdate()
select 'Your Code'=convert(DateTime,con vert(int,g etdate()), 101)
select 'My code'=cast(convert(varchar ,getdate() ,112) as datetime)
/* Results
Today
-------------------------- -
2000-01-19 12:27:34.630
Your Code
-------------------------- -
2000-01-20 00:00:00.000
My code
-------------------------- -
2000-01-19 00:00:00.000
*/
PD: Post more information about your last comment. Let me help you.
Be careful when removing time portion from datetime datatype. Check next situation:
set nocount on
select 'Today'=getdate()
select 'Your Code'=convert(DateTime,con
select 'My code'=cast(convert(varchar
/* Results
Today
--------------------------
2000-01-19 12:27:34.630
Your Code
--------------------------
2000-01-20 00:00:00.000
My code
--------------------------
2000-01-19 00:00:00.000
*/
PD: Post more information about your last comment. Let me help you.
ASKER
I see. Thanks for that tip. Here's my new version of the first part ofthe trigger. This works OK.
IF
(
SELECT COUNT(*)
FROM StaffTimesAgg a
JOIN Inserted i
on CAST(convert(varchar,a.Arc hiveTime,1 12)AS datetime)=CAST(convert(var char,i.Arc hiveTime,1 12) AS datetime)
AND a.StaffID=i.StaffID
AND a.State=i.State
)=0
BEGIN
INSERT StaffTimesAgg
(
ArchiveTime,
StaffID,
State,
Amount
)
SELECT
cast(convert(varchar,i.Arc hiveTime,1 12) as datetime) Archivetime,
i.StaffID,
i.State,
SUM(ISNULL(i.Amount,0)) Amount
FROM Inserted i
GROUP BY cast(convert(varchar,i.Arc hiveTime,1 12) as datetime), i.StaffID, i.State
END
ELSE
Then for the other condition when there are matching records in table2 I need to aggregate records from both the inserted table and table2 where 3 fields match (one of the 3 fields is a conversion of the date field). So, i tried a cursor which i can't get to work:
--DEALLOCATE i
DECLARE @Amount Float
DECLARE @StaffID int
DECLARE @Archivetime datetime
DECLARE @State int
DECLARE i CURSOR FOR
SELECT cast(convert(varchar,Archi veTime,112 ), StaffID, State, Amount FROM Inserted
OPEN i
FETCH NEXT FROM i INTO @Archivetime, @StaffID, @State, @Amount
WHILE @@FETCH_STATUS = 0
--BEGIN
UPDATE a
SET a.Amount=ISNULL(a.Amount,0 )+ISNULL(@ Amount,0)
FROM dbo.StaffTimesAgg a
WHERE
a.StaffID=@StaffID
AND cast(convert(varchar,a.Arc hiveTime,1 12)as datetime)=cast(convert(var char,@Arch iveTime,11 2)as datetime)
AND a.State=@State
FETCH NEXT FROM i INTO @Archivetime, @StaffID, @State, @Amount
CLOSE i
DEALLOCATE i
IF
(
SELECT COUNT(*)
FROM StaffTimesAgg a
JOIN Inserted i
on CAST(convert(varchar,a.Arc
AND a.StaffID=i.StaffID
AND a.State=i.State
)=0
BEGIN
INSERT StaffTimesAgg
(
ArchiveTime,
StaffID,
State,
Amount
)
SELECT
cast(convert(varchar,i.Arc
i.StaffID,
i.State,
SUM(ISNULL(i.Amount,0)) Amount
FROM Inserted i
GROUP BY cast(convert(varchar,i.Arc
END
ELSE
Then for the other condition when there are matching records in table2 I need to aggregate records from both the inserted table and table2 where 3 fields match (one of the 3 fields is a conversion of the date field). So, i tried a cursor which i can't get to work:
--DEALLOCATE i
DECLARE @Amount Float
DECLARE @StaffID int
DECLARE @Archivetime datetime
DECLARE @State int
DECLARE i CURSOR FOR
SELECT cast(convert(varchar,Archi
OPEN i
FETCH NEXT FROM i INTO @Archivetime, @StaffID, @State, @Amount
WHILE @@FETCH_STATUS = 0
--BEGIN
UPDATE a
SET a.Amount=ISNULL(a.Amount,0
FROM dbo.StaffTimesAgg a
WHERE
a.StaffID=@StaffID
AND cast(convert(varchar,a.Arc
AND a.State=@State
FETCH NEXT FROM i INTO @Archivetime, @StaffID, @State, @Amount
CLOSE i
DEALLOCATE i
Ok, I understood your problem “Multirow Considerations”. Check code above:
create TRIGGER dbo.trgUpdateAgg ON StaffTimes
for insert
as
begin
if (select count(*)
from StaffTimesAgg a
join Inserted i
on CAST(convert(varchar,a.Arc hiveTime,1 12)AS datetime)
=CAST(convert(varchar,i.Ar chiveTime, 112)AS datetime)
AND a.StaffID=i.StaffID
AND a.State=i.State)=0
BEGIN
INSERT StaffTimesAgg (ArchiveTime
,StaffID
,State
,Amount)
SELECT cast(convert(varchar,i.Arc hiveTime,1 12) as datetime) Archivetime
,i.StaffID
,i.State
,SUM(ISNULL(i.Amount,0)) Amount
FROM Inserted i
GROUP BY cast(convert(varchar,i.Arc hiveTime,1 12) as datetime)
,i.StaffID
,i.State
END
else
begin
declare @Archivetime datetime
,@StaffID int
,@State int
,@Amount Float
declare cr_inserted cursor local
for select cast(convert(varchar,Archi veTime,112 ) as datetime)
,StaffID
,State
,sum(isnull(Amount,0))
from inserted
group by cast(convert(varchar,Archi veTime,112 ) as datetime)
,StaffID
,State
open cr_inserted
while (1=1)
begin
fetch next from cr_inserted into
@Archivetime,@StaffID,@Sta te,@Amount
if @@fetch_status<>0 break
update StaffTimesAgg
set Amount=Amount+@Amount
where Archivetime
=@Archivetime and
StaffID=@StaffID and
State=@State
end
end
end
create TRIGGER dbo.trgUpdateAgg ON StaffTimes
for insert
as
begin
if (select count(*)
from StaffTimesAgg a
join Inserted i
on CAST(convert(varchar,a.Arc
=CAST(convert(varchar,i.Ar
AND a.StaffID=i.StaffID
AND a.State=i.State)=0
BEGIN
INSERT StaffTimesAgg (ArchiveTime
,StaffID
,State
,Amount)
SELECT cast(convert(varchar,i.Arc
,i.StaffID
,i.State
,SUM(ISNULL(i.Amount,0)) Amount
FROM Inserted i
GROUP BY cast(convert(varchar,i.Arc
,i.StaffID
,i.State
END
else
begin
declare @Archivetime datetime
,@StaffID int
,@State int
,@Amount Float
declare cr_inserted cursor local
for select cast(convert(varchar,Archi
,StaffID
,State
,sum(isnull(Amount,0))
from inserted
group by cast(convert(varchar,Archi
,StaffID
,State
open cr_inserted
while (1=1)
begin
fetch next from cr_inserted into
@Archivetime,@StaffID,@Sta
if @@fetch_status<>0 break
update StaffTimesAgg
set Amount=Amount+@Amount
where Archivetime
=@Archivetime and
StaffID=@StaffID and
State=@State
end
end
end
ASKER
Ok, very good. That appears to work well. Thanks again.
ASKER