Iterate inserted in trigger - sql

This SQL Server trigger works correctly for a single insert
CREATE TRIGGER [dbo].[DebitSale]
ON [dbo].[OrderDetails]
AFTER INSERT, UPDATE
AS
DECLARE #OrderId bigint
DECLARE #OrderNr int
DECLARE #TaxRate decimal(9,2)
DECLARE #Tax decimal(9,2)
DECLARE #Total decimal(9,2)
DECLARE #syncRate decimal(9,8)
DECLARE #Net decimal(9,2)
DECLARE #OldNet decimal(9,2)
DECLARE #ExactFee decimal(9,2)
DECLARE #Fee decimal(9,2)
DECLARE #JobId bigint
DECLARE #ItemCode nvarchar(35)
IF EXISTS ( SELECT 0 FROM inserted )
BEGIN
SELECT #syncRate = SyncRate
FROM dbo.[UserAccount]
WHERE Id = 0
SELECT #Net = i.NrUnits * i.UnitNet from inserted i
SELECT #OldNet = d.NrUnits * d.UnitNet from deleted d
IF(#Net=#OldNet)
BEGIN
RETURN
END
SELECT #OrderId = i.OrderId, #JobId = i.JobId, #ItemCode = i.ItemCode FROM inserted i
SELECT #OrderNr = OrderNr, #TaxRate = TaxRate FROM Orders WHERE OrderId = #OrderId
SET #Tax = #Net * #TaxRate / 100
SET #Total = #Net + #Tax
SET #ExactFee = #Total * #syncRate
SET #Fee = FLOOR(#ExactFee * 100)/100
IF(#Fee >= 0.01)
BEGIN
IF #JobId IS NULL
INSERT INTO SubscriptionTransactions
(ItemValue, OrderNr, TransactionCredit, TransactionDate, TransactionDebit, TransactionDescription, TransactionType)
VALUES (#Total, #OrderNr, 0, GetDate(), #Fee, #ItemCode, 'Item')
ELSE
INSERT INTO SubscriptionTransactions
(ItemValue, OrderNr, TransactionCredit, TransactionDate, TransactionDebit, TransactionDescription, TransactionType)
VALUES (#Total, #OrderNr, 0, GetDate(), #Fee, #ItemCode, 'Job')
END
END
However we sometimes get multiple rows in inserted so I included a loop like this
ALTER TRIGGER [dbo].[DebitSale]
ON [dbo].[OrderDetails]
AFTER INSERT, UPDATE
AS
BEGIN
DECLARE #OrderId bigint
DECLARE #OrderDetailId bigint
DECLARE #OrderNr int
DECLARE #TaxRate decimal(9,2)
DECLARE #Tax decimal(9,2)
DECLARE #Total decimal(9,2)
DECLARE #syncRate decimal(9,8)
DECLARE #Net decimal(9,2)
DECLARE #OldNet decimal(9,2)
DECLARE #ExactFee decimal(9,2)
DECLARE #Fee decimal(9,2)
DECLARE #JobId bigint
DECLARE #ItemCode nvarchar(35)
SELECT #syncRate = SyncRate
FROM dbo.[UserAccount]
WHERE Id = 0
DECLARE #current INT = 0;
DECLARE #InsertedCount int
SELECT #InsertedCount = Count(*) FROM inserted
DECLARE #Thing nvarchar(max)
SELECT #Thing ='InsertedCount ' + CAST(#InsertedCount AS VARCHAR)
INSERT INTO DebugTable (DebugColumn) VALUES (#Thing)
WHILE #current <= #InsertedCount
BEGIN
SELECT #Thing ='current ' + CAST(#current AS VARCHAR)
INSERT INTO DebugTable (DebugColumn) VALUES (#Thing)
SELECT #OrderDetailId AS OrderDetailId from inserted i
ORDER BY OrderDetailId
OFFSET #current ROWS
FETCH NEXT 1 ROWS ONLY
SET #current = #current + 1;
SELECT #Net = NrUnits * UnitNet FROM inserted i WHERE i.OrderDetailId= #OrderDetailId
SELECT #OldNet = d.NrUnits * d.UnitNet from deleted d where d.OrderDetailId= #OrderDetailId
IF(#Net=#OldNet)
CONTINUE
SELECT #OrderId = i.OrderId, #JobId = i.JobId, #ItemCode = i.ItemCode FROM inserted i WHERE i.OrderDetailId= #OrderDetailId
SELECT #OrderNr = OrderNr, #TaxRate = TaxRate FROM Orders WHERE OrderId = #OrderId
SET #Tax = #Net * #TaxRate / 100
SET #Total = #Net + #Tax
SET #ExactFee = #Total * #syncRate
SET #Fee = FLOOR(#ExactFee * 100)/100
IF(#Fee < 0.01)
CONTINUE
IF (#JobId IS NULL)
INSERT INTO SubscriptionTransactions
(ItemValue, OrderNr, TransactionCredit, TransactionDate, TransactionDebit, TransactionDescription, TransactionType)
VALUES (#Total, #OrderNr, 0, GetDate(), #Fee, #ItemCode, 'Item')
ELSE
INSERT INTO SubscriptionTransactions
(ItemValue, OrderNr, TransactionCredit, TransactionDate, TransactionDebit, TransactionDescription, TransactionType)
VALUES (#Total, #OrderNr, 0, GetDate(), #Fee, #ItemCode, 'Job')
END
INSERT INTO DebugTable (DebugColumn) VALUES (#ItemCode)
END
This is a remote server that services a Web API. I don't have access to remote debugging so I've put some debug code in that logs a couple of lines to a DebugTable. The trigger writes to DebugTable if I execute an insert statement in SSMS, but doesn't update Transactions.
The Web API executes a merge statement in which case nothing is written to DebugTable and Transactions are not updated. I'm not sure if the new trigger is even firing.
I know there is a lot of TSQL here, but given the original trigger seems to work for a single insert, and that trigger is unchanged except for wrapping it in a loop, I assume I've got the loop wrong.
I expect some will spurn the loop, but in mitigation, there are rarely more than 2 rows inserted at a time.
How do I loop through inserted in a trigger?

Your main insert should be something like the following i.e. there is no need for a loop. One should always aim for set based operations in SQL if at all possible. The key points are:
JOIN the relevant tables together
use CROSS APPLY to avoid having to repeat calculations
use the WHERE clause to exclude cases you are currently using CONTINUE for.
I've tried to match your logic as best I can. But without being able to test it I can't be sure it works. You will want to run it through a few tests to be sure its working exactly as you wish.
And I leave the debugging/logging code as an exercise for you.
INSERT INTO dbo.SubscriptionTransactions (ItemValue, OrderNr, TransactionCredit, TransactionDate, TransactionDebit, TransactionDescription, TransactionType)
SELECT
T.Total
, O.OrderNr
, 0
, GetDate()
, F.Fee
, I.ItemCode
, CASE WHEN I.JobId IS NULL THEN 'Job' ELSE 'Item' END
FROM Inserted I
-- Deleted won't exist for an insert
LEFT JOIN Deleted D on D.OrderDetailId = I.OrderDetailId
INNER JOIN Orders O on O.OrderId = I.OrderId
CROSS APPLY (
VALUES (I.NrUnits * I.UnitNet, D.NrUnits * D.UnitNet)
) N (Net, OldNet)
CROSS APPLY (
VALUES (N.Net * (1.0 + N.Net * O.TaxRate / 100))
) T (Total)
CROSS APPLY (
VALUES (FLOOR(T.Total * #SyncRate * 100)/100)
) F (Fee)
WHERE (N.Net != N.OldNet OR D.OrderDetailId IS NULL) -- First continue condition
AND Fee >= 0.01; -- Second continue condition

Related

SQL Query - Merge two types of objects with the same value

I want to find PC model pairs with the same speed and memory. These pairs are listed only once.
Here is my data and desired results:
desired results: https://i.imgur.com/cJBdrvq.png
data: https://i.imgur.com/t8LiJ7G.png
I did get results but the query is too long, I know there is a shorter way. Hope everyone help me.
Here is my query
DECLARE #FOR INT = 1
DECLARE #SPEED INT
DECLARE #RAM INT
DECLARE #MODEL INT
DECLARE #LIST TABLE(SPEED INT, RAM INT)
DECLARE #LISTMODEL TABLE(MODEL INT)
DECLARE #RESULT TABLE(PC1 INT, PC2 INT)
DECLARE #RESULTREAL TABLE(COUPLE NVARCHAR(20), SPEED INT, RAM INT)
DECLARE #COUNT INT
WHILE(1=1)
BEGIN
IF(NOT EXISTS(SELECT TOP(1) SPEED FROM #LIST))
BEGIN
INSERT #LIST(SPEED,RAM)
SELECT speed,ram
FROM VW_count
END
BREAK
END
SET #COUNT = (SELECT COUNT(SPEED) FROM #LIST)
WHILE #FOR <= #COUNT
BEGIN
SET #SPEED = (SELECT KETQUA.SPEED FROM (SELECT ROW_NUMBER() OVER (ORDER BY SPEED) AS STT, SPEED FROM #LIST) AS KETQUA WHERE KETQUA.STT = 1)
SET #RAM = (SELECT KETQUA.RAM FROM (SELECT ROW_NUMBER() OVER (ORDER BY RAM) AS STT, RAM FROM #LIST) AS KETQUA WHERE KETQUA.STT = 1)
IF #SPEED IS NULL
BEGIN
BREAK
END
ELSE
BEGIN
IF(EXISTS(SELECT speed FROM PC WHERE speed = #SPEED AND ram = #RAM))
BEGIN
INSERT #LISTMODEL(MODEL)
SELECT model FROM PC WHERE speed = #SPEED AND ram = #RAM
INSERT #RESULT(PC1,PC2)
SELECT DISTINCT L1.MODEL, L2.MODEL FROM #LISTMODEL AS L1 , #LISTMODEL AS L2
INSERT #RESULTREAL(COUPLE,SPEED,RAM)
SELECT CONCAT(R1.PC1, ', ', R1.PC2), #SPEED, #RAM FROM #RESULT R1 WHERE R1.PC1 > R1.PC2 OR NOT EXISTS (SELECT * FROM #RESULT R2 WHERE R2.PC1 = R1.PC2 AND R1.PC2 = R2.PC1)
END
DELETE #RESULT
DELETE #LISTMODEL
END
SET #FOR = #FOR + 1
DELETE TOP(1) FROM #LIST
CONTINUE
END
SELECT * FROM #RESULTREAL
It's normally a bad idea to use procedural statements when you could also use set-based logic.
You could make a SELECT query using a self-join on table [PC] based on the value of the [speed] and [ram] fields, but where the [model] value of the second table is larger than that of the first table. Something like this:
DECLARE #RESULTREAL TABLE(COUPLE NVARCHAR(20), SPEED INT, RAM INT);
INSERT INTO #RESULTREAL
SELECT
CAST(T1.[model] AS NVARCHAR) + N', ' + CAST(T2.[model] AS NVARCHAR),
T1.[speed],
T1.[ram]
FROM
[PC] AS T1
INNER JOIN [PC] AS T2 ON
T2.[speed] = T1.[speed] AND
T2.[ram] = T1.[ram]
WHERE
T2.[model] > T1.[model];

SQL While Loop Insert with values from another table

I am trying to create a SQL While loop that will update a temp table with values from another table. Values from the other table:
477286
560565
499330
391827
127375
526354
501736
357359
410433
500946
261297
377667
135931
235691
247239
143672
548752
471945
...
Wrote the following, however, it only inserts the last value multiple times over.
Here is the code:
USE Reports
GO
CREATE TABLE #TempTable (CreatedByID int, LastUpdatedByID int, ID int,
AlertDE int, Alert char(50), StartDTTM datetime, EndDTTM datetime,
IsInactiveFLAG char(1),AlertDetails char(1));
DECLARE #numrows INT
SELECT #numrows = COUNT(*) FROM [Reports].[dbo].[Eligible]
DECLARE #id int
DECLARE #LoopCount INT = 1
DECLARE #count int = #numrows
SELECT #id = [id] FROM [Reports].[dbo].[Eligible]
WHILE (#LoopCount <= #count)
BEGIN
INSERT INTO #TempTable (CreatedByID, LastUpdatedByID, ID, AlertDE, Alert, StartDTTM, EndDTTM, IsInactiveFLAG,AlertDetails)
VALUES (52,52,#id,0,'Eligible',CURRENT_TIMESTAMP,'1900-01-01
00:00:00.000','N','')
SET #LoopCount = #LoopCount + 1
END
SELECT * FROM #TempTable
DROP TABLE #TempTable
I am assuming I have to tell it to loop through the values in the other table somehow but I am not positive if that is the right approach or if in general I am taking the long way around the bus.
Why are you using a loop? You can do this with an insert . . . select statement:
INSERT INTO #TempTable (CreatedByID, LastUpdatedByID, ID, AlertDE, Alert, StartDTTM, EndDTTM, IsInactiveFLAG, AlertDetails)
SELECT 52, 52, e.id, 0, 'Eligible', CURRENT_TIMESTAMP, '1900-01-01 00:00:00.000', 'N', ''
FROM [Reports].[dbo].[Eligible] e ;
See eg https://www.w3schools.com/sql/sql_insert_into_select.asp for more info.
GMR, I found a way to accomplish my need which is similar to yours. Hopefully this will help you too.
DECLARE
#LoopId int
,#TheOrderNumber varchar(20)
DECLARE #CheckThisItem TABLE
(
LoopId int not null identity(1,1)
,TheOrderNumber varchar(20) not null
)
INSERT #CheckThisItem
SELECT Order_Number AS TheOrderNumber
FROM [dbo].[Table_Storing_Order_Number] ORDER BY Order_Number ASC
SET #LoopId = ##rowcount
WHILE #LoopId > 0
BEGIN
SELECT #TheOrderNumber = TheOrderNumber
FROM #CheckThisItem
WHERE LoopId = #LoopId
-- Start inserting record pulled for while loop
INSERT [dbo].[The_Destination_Table]
SELECT TOP (1)
A, B, C, D
FROM [dbo].[Source_Table] ST
WHERE
ST.Order_Number = #TheOrderNumber
-- Set number to reduce loop counter
SET #LoopId = #LoopId - 1
END;

How to make this code more professional look?

DECLARE #Coid INT
DECLARE #DTRID INT
DECLARE #EMPID INT
DECLARE #DATE datetime
SELECT TOP 1 #EMPID = tblEmployees.Id, #Coid = tblEmployees.CompanyId, #DATE = tblDailyTimeRecord.TimeIn, #DTRID = tblDailyTimeRecord.Id FROM tblEmployees INNER JOIN tblDailyTimeRecord ON tblEmployees.Id = tblDailyTimeRecord.EmployeeId WHERE tblDailyTimeRecord.Date = CONVERT(date, GETDATE()) AND tblDailyTimeRecord.TimeOut IS NULL ORDER BY tblDailyTimeRecord.ID DESC
IF #Coid IS NULL
BEGIN
DECLARE #IdentityValue TABLE ( ContactID int,EmpId int,DATE datetime)
INSERT INTO [tblDailyTimeRecord]([EmployeeId],[Date],[TimeOut],[IsModified],[CompanyId])
OUTPUT INSERTED.Id,INSERTED.EmployeeId,INSERTED.TimeOut INTO #IdentityValue
Select Id,CONVERT(date, GETDATE()),GETDATE(),0,CompanyId From tblEmployees Where AccessCode = 'GI0056'
INSERT INTO tblTimeLog([EmployeeId],[Time],[Type],[TimeLogSourceId],[CreationDate])
Select EmpId,DATE,2,11,GETDATE() From #IdentityValue
END
ELSE
BEGIN
DECLARE #PAIR int
DECLARE #TIMEOUT datetime
SET #TIMEOUT = GETDATE()
IF #DATE IS NULL
SET #PAIR = 0
ELSE
SET #PAIR = 1
UPDATE [tblDailyTimeRecord] SET TimeOut = #TIMEOUT, PairNo = #PAIR WHERE ID = #DTRID
INSERT INTO tblTimeLog([EmployeeId],[Time],[Type],[TimeLogSourceId],[CreationDate])
VALUES (#EMPID,#TIMEOUT,2,11,#TIMEOUT)
END
Just general formatting rules:
1. All declaration better are in the beginning.
2. Be consistent: all reserved words in capital
3. Do not use reserved words for column names.
4. Comment your code.
5. Use unified intends.
6. Finish statements with semicolon.
7. If you can, use CASE instead of IF SET.
8. Use short aliases for tables and views.
9. Name variables in SELECT statement, then it will be clear what goes where.
Have I forgot something?
Logic/Design.
1. Instead of multiple variables you could use temp table variable or just temp table. It would make code shorter and more readable.
2. First SELECT returns one row, but in the INSERT statement you might insert something completely irrelevant.
3. Having the same data in two tables might be a sign of bad design.
4. Having Date and Datetime for the same event in the same row is very suspicious.
It might be as the code below. Hope that helps.
DECLARE #Coid INT;
DECLARE #DTRID INT;
DECLARE #EMPID INT;
DECLARE #DATE DATETIME;
DECLARE #PAIR INT;
DECLARE #TIMEOUT DATETIME;
DECLARE #IdentityValue TABLE (
ContactID int,
EmpId int,
ContactDate DATETIME
);
-- Select ONLY one row
SELECT TOP 1
#EMPID = e.Id,
#Coid = e.CompanyId,
#DATE = tr.TimeIn,
#DTRID = tr.Id,
#TIMEOUT = GETDATE(),
#PAIR = CASE WHEN tr.TimeIn IS NULL THEN 0 ELSE 1 END
FROM tblEmployees as e
INNER JOIN tblDailyTimeRecord as tr
ON e.Id = tr.EmployeeId
WHERE tr.Date = CONVERT(DATE, GETDATE())
AND tr.TimeOut IS NULL
ORDER BY tr.ID DESC;
IF #Coid IS NULL
BEGIN
-- Insert more than one row or might insert nothing
INSERT INTO [tblDailyTimeRecord] (
[EmployeeId],
[Date],
[TimeOut],
[IsModified],
[CompanyId]
)
OUTPUT INSERTED.Id,
INSERTED.EmployeeId,
INSERTED.TimeOut
INTO #IdentityValue
SELECT Id as [EmployeeId],
CONVERT(DATE, GETDATE()) as [Date],
#TIMEOUT as [TimeOut],
0 as [IsModified],
CompanyId
FROM tblEmployees
WHERE AccessCode = 'GI0056';
INSERT INTO tblTimeLog(
[EmployeeId],
[Time],
[Type],
[TimeLogSourceId],
[CreationDate])
SELECT EmpId as [EmployeeId],
ContactDate as [Time],
2 as [Type],
11 as [TimeLogSourceId],
#TIMEOUT as [CreationDate]
FROM #IdentityValue;
END
ELSE
BEGIN
UPDATE [tblDailyTimeRecord]
SET TimeOut = #TIMEOUT,
PairNo = #PAIR
WHERE ID = #DTRID
INSERT INTO tblTimeLog(
[EmployeeId],
[Time],
[Type],
[TimeLogSourceId],
[CreationDate]
) VALUES (
#EMPID,
#TIMEOUT,
2,
11,
#TIMEOUT
);
END

Subquery returned more than one value error

I am using the following query, but it is throwing an error. It is working fine for some scenarios, depending on the id, but not for all.
Subquery returned more than 1 value. This is not permitted when the
subquery follows =, !=, <, <= , >, >= or when the subquery is used as
an expression.
Set #NoOfRows = (Select COUNT(*) from #TempT)
While #i <= #NoOfRows
Begin
SET #Voucher_No=( select V_No from #TempT where RowID=#i)
SET #Voucher_Type_No=( select voucher_type_no from #TempT where RowID=#i)
SET #Voucher_Id=( select Voucher_Id from #TempT where RowID=#i)
set #strPartyName=''
set #strPartyName = (Select Party_Name from Cheque_Book where Voucher_No= #Voucher_No and Voucher_Type_No= #Voucher_Type_No and Company_No= #Comp_No and Bank_Account_No= #dbc_Account )
if NULLIF(#strPartyName,'') IS NULL
begin
set #strPartyName =(Select a.account_name from Voucher v inner join account a on v.Account_No = a.account_No where v.Voucher_Id= #Voucher_Id)
Update #TempT Set Party_Name =#strPartyName Where RowID =#i
set #i=#i+1
end
End
Select * from #TempT
Rather than setting variable using sub-query, set variable as shown below.
SELECT #NoOfRows = COUNT(*) FROM #TempT
WHILE #i <= #NoOfRows
BEGIN
SELECT #Voucher_No = V_No FROM #TempT WHERE RowID=#i
SELECT #Voucher_Type_No = voucher_type_no FROM #TempT WHERE RowID=#i
SELECT #Voucher_Id = Voucher_Id FROM #TempT where RowID=#i
SET #strPartyName=''
SELECT #strPartyName = Party_Name FROM Cheque_Book WHERE Voucher_No = #Voucher_No AND Voucher_Type_No = #Voucher_Type_No AND Company_No= #Comp_No AND Bank_Account_No= #dbc_Account
IF NULLIF(#strPartyName,'') IS NULL
BEGIN
SELECT #strPartyName = a.account_name FROM Voucher v INNER JOIN account a ON v.Account_No = a.account_No WHERE v.Voucher_Id= #Voucher_Id
UPDATE #TempT SET Party_Name = #strPartyName WHERE RowID = #i
SET #i = #i + 1
END
END
SELECT * FROM #TempT
Its show that your sub-query return more than one value.
You have to modify your sub-query with TOP keyword or give filter (where condition and order by ) more which return only one value.
While #i <= #NoOfRows
Begin
SET #Voucher_No=( select top 1 V_No from #TempT where RowID=#i)
SET #Voucher_Type_No=( select top 1 voucher_type_no from #TempT where RowID=#i)
SET #Voucher_Id=( select top1 Voucher_Id from #TempT where RowID=#i)
......
END
To resolve the problem, you just only run the actual select query in while loop which gives the result of more than 2 value like
While #i <= #NoOfRows
Begin
--SET #Voucher_No=(
select V_No from #TempT where RowID=#i --)
--SET #Voucher_Type_No=(
select voucher_type_no from #TempT where RowID=#i --)
--SET #Voucher_Id=(
select Voucher_Id from #TempT where RowID=#i --)
......
END
UPDATED
This is sample data to understand what happened with you and how to resolve it.
declare #department table (deptid int, name varchar(50))
declare #emp table (id int, name varchar(50), deptid int)
insert into #department values (1,'d1'), (2,'d2'),(3,'d3'),(4,'d4')
insert into #emp values(1,'ajay',1), (2,'ajay1',1),(3,'ajay3' ,2),(4,'ajay4' ,3),(5,'ajay5' ,4)
select * from #department where deptid = 1
/* suppose your sub-query like */
--1. this give result
select * from #department where deptid = (select deptid from #emp where id = 1)
--2. this give result, but may be get wrong result as it take top 1.
select * from #department where deptid = (select top 1 deptid from #emp )
--3. this give error same you have
select * from #department where deptid = (select deptid from #emp)
--to resolve the above error, just uncomment below sub-query.
--select deptid from #emp
I see answers here for the issue where the following queries fail because their subqueries return multiple values:
SET #Voucher_No = (SELECT [V_No] FROM #TempT WHERE [RowID] = #i);
SET #Voucher_Type_No = (SELECT [voucher_type_no] FROM #TempT WHERE [RowID] = #i);
SET #Voucher_Id = (SELECT [Voucher_Id] FROM #TempT WHERE [RowID] = #i);
There are mainly two proposed solutions in those answers:
SET #Variable = (SELECT TOP (1) [Field] FROM [Table] WHERE ...);, or
SELECT #Variable = [Field] FROM [Table] WHERE ...);.
To my surprise, the second approach is considered to be the preferred approach. There are a few important things to consider, however.
First: if the SELECT-query returns multiple results, the value of #Variable will become the last retrieved value from the query's result set. This has to be regarded when an ORDER BY clause is specified.
So the query below will return 5 instead of 1:
DECLARE #TempTable TABLE ([ID] INT);
INSERT INTO #TempTable VALUES (1), (3), (2), (5), (4);
DECLARE #Variable INT = 42;
SELECT #Variable = [ID] FROM #TempTable ORDER BY [ID];
SELECT #Variable AS [#Variable];
Second: if #Variable already contains a value and the SELECT query does not produce any results (0 rows), the value of #Variable remains unchanged!
So the query below will produce result 42 instead of NULL:
DECLARE #TempTable TABLE ([ID] INT);
INSERT INTO #TempTable VALUES (1), (3), (2), (5), (4);
DECLARE #Variable INT = 42;
SELECT #Variable = [ID] FROM #TempTable WHERE [ID] = 6;
SELECT #Variable AS [#Variable];
For all these reasons, my personal preference lies with the SET #Variable = (SELECT TOP (1) ...) approach.

While Loop in TSQL with Sum totals

I have the following TSQL Statement, I am trying to figure out how I can keep getting the results (100 rows at a time), store them in a variable (as I will have to add the totals after each select) and continue to select in a while loop until no more records are found and then return the variable totals to the calling function.
SELECT [OrderUser].OrderUserId, ISNULL(SUM(total.FileSize), 0), ISNULL(SUM(total.CompressedFileSize), 0)
FROM
(
SELECT DISTINCT TOP(100) ProductSize.OrderUserId, ProductSize.FileInfoId,
CAST(ProductSize.FileSize AS BIGINT) AS FileSize,
CAST(ProductSize.CompressedFileSize AS BIGINT) AS CompressedFileSize
FROM ProductSize WITH (NOLOCK)
INNER JOIN [Version] ON ProductSize.VersionId = [Version].VersionId
) AS total RIGHT OUTER JOIN [OrderUser] WITH (NOLOCK) ON total.OrderUserId = [OrderUser].OrderUserId
WHERE NOT ([OrderUser].isCustomer = 1 AND [OrderUser].isEndOrderUser = 0 OR [OrderUser].isLocation = 1)
AND [OrderUser].OrderUserId = 1
GROUP BY [OrderUser].OrderUserId
Depending on the clustered index, if its by numbered id, then use the code below. If its by date, go in 10 - 60 minute increments. keep an eye on performance of other things, but the lovely part of this code is you can start and stop at anytime if you push the results to permanent temp table (real table, just temp)
Here's a sample:
declare #count int
Declare #batch int
declare #max int
create table #temp (id int identity(1,1) primary key, Batch int, value int)
select #max = max(OrderUserId), #count = 0, #batch = 1000 from table
while (#count < #max)
begin
insert into #temp (batch,value)
select #count, Sum(stuffs)
from table
where orderId >= #count
and orderid < #count + #batch
Set #count = #count + #batch
waitfor delay ('00:00:01')
Raiserror('On Batch %d',0,1,#Count) with nowait /* Will print progess */
end