[AccessD] Is a cursor the way to go

Salakhetdinov Shamil mcp2004 at mail.ru
Sun May 27 01:43:37 CDT 2012


Hi Paul --

It's definitely a bad design case as noted here by Arthur and others but it looks like it can be handled without cursors at all:

--
-- Step ONE - Create sample tables
-- 
IF  EXISTS (SELECT * FROM sys.objects WHERE object_id = OBJECT_ID(N'[dbo].[POAllocation]') AND type in (N'U'))
DROP TABLE [dbo].[POAllocation]
GO

IF  EXISTS (SELECT * FROM sys.objects WHERE object_id = OBJECT_ID(N'[dbo].[PODetail]') AND type in (N'U'))
DROP TABLE [dbo].[PODetail]
GO

CREATE TABLE POAllocation (PONumber int, Allocated money)
CREATE TABLE PODetail (PONumber int, Amount money, IsAllocated bit, RowID int IDENTITY(1,1) NOT NULL)
go

-- allocation is greater than details totals
INSERT POAllocation VALUES (123456, 141.00)
INSERT PODetail VALUES (123456, 50.00, 0)
INSERT PODetail VALUES (123456, 20.00, 0)
INSERT PODetail VALUES (123456, 76.00, 0)
GO
-- allocation is less than details totals
INSERT POAllocation VALUES (789012, 253.00)
INSERT PODetail VALUES (789012, 99.00, 0)
INSERT PODetail VALUES (789012, 101.00, 0)
GO
-- allocation is equal to details totals
INSERT POAllocation VALUES (345678, 101.00)
INSERT PODetail VALUES (345678, 9.00, 0)
INSERT PODetail VALUES (345678, 31.00, 0)
INSERT PODetail VALUES (345678, 20.00, 0)
INSERT PODetail VALUES (345678, 30.00, 0)
INSERT PODetail VALUES (345678, 11.00, 0)
GO
-- allocation without details
INSERT POAllocation VALUES (567890, 99.00)
GO
-- zero allocation, zero details
INSERT POAllocation VALUES (901234, 0.00)
GO

select * from POAllocation
select * from PODetail

--
--  STEP TWO - Test
-- 

DECLARE @AllocationTbl TABLE 
(
 RowId int, 
 PONumber int, 
 Amount money, 
 RunningTotal money, 
 Allocated money, 
 IsAllocated bit
 )
 
DECLARE @RunningTotal money
DECLARE @PONumber int
 
SET @RunningTotal = 0
set @PONumber = null

INSERT INTO @AllocationTbl 
SELECT RowId, a.PONumber, Amount, null, a.Allocated, null
FROM PODetail d, POAllocation a
where d.PONumber = a.PONumber
ORDER BY a.PONumber, RowId

UPDATE @AllocationTbl
SET @RunningTotal = RunningTotal = 
 case 
  when (@PONumber = PONumber) then
     @RunningTotal + Amount
  else
     Amount
 end,
 @PONumber = PONumber,
 IsAllocated = case 
  when (@RunningTotal <= Allocated) 
   then 1 
 else 0 
 end  
FROM @AllocationTbl
 
-- SELECT * FROM @AllocationTbl

update PODetail 
  set IsAllocated = a.IsAllocated
from PODetail d, @AllocationTbl a
where 
  d.PONumber = a.PONumber and
  d.RowId = a.RowId

-- select * from POAllocation
select * from PODetail

--
-- Result
--
-- 123456	50.00	1	1
-- 123456	20.00	1	2
-- 123456	76.00	0	3
-- 789012	99.00	1	4
-- 789012	101.00	1	5
-- 345678	9.00	1	6
-- 345678	31.00	1	7
-- 345678	20.00	1	8
-- 345678	30.00	1	9
-- 345678	11.00	1	10

Enjoy!  :)(But verify that  it will work for your case - tested here with MS SQL 2008 R2 Express Edition)

Credit: Calculating Running Totals in SQL Server 2005, The optimal solution?
http://geekswithblogs.net/Rhames/archive/2008/10/28/calculating-running-totals-in-sql-server-2005---the-optimal.aspx

Thank you.

-- Shamil


Fri, 25 May 2012 13:35:21 +0100 от Paul Hartland <paul.hartland at googlemail.com>:
> To all,
> 
> I will try and explain the problem as best as I possibly can, for this
> purpose lets say I have two tables, PODetail which holds detail records for
> a purchase order, and a table containing a value which we have currently
> allocated to a single purchase order number POAllocation
> 
> PODetail
> PoNumber    Amount     Allocated    RowID
> 123456          50.00             0              1
> 123456          20.00             0              2
> 123456          76.00             0              3
> 
> POAllocation
> PONumber    Allocated
> 123456          141.00
> 
> What I need to do is update the Allocated field in PODetail with a value,
> the way I want to do this is get the PO number and allocated amount from
> POAllocation and then loop through the PODetail records updating the
> Allocated field, so I would come to record (rowid) 1 if the allocated
> amount is less than 50.00 then update the allocated field with that value,
> if the allocated amount is great than 50.00 then update the allocated field
> to 50.00, take 50.00 away from 141.00 to get 91.00 then report the process
> for record (rowid) 2.
> 
> I am thinking/in middle of writing a cursor inside a cursor, anyone else
> any better ideas on how to do this.
> 
> Thanks in advance for any help.
> 
> 
> -- 
> Paul Hartland
> paul.hartland at googlemail.com
> -- 



More information about the AccessD mailing list