I've got the following three tables defined:
table 'A':
-------------------
majorID | bigint (primary key)
-------------------
table 'B':
-------------------
majorID | bigint (foreign key to table 'A's majorID)
minorID | bigint (primary key)
totalSize | bigint
-------------------
table 'C':
-------------------
objectID | bigint (primary key)
majorID | bigint (foreign key to table 'A's majorID)
minorID | bigint (foreign key to table 'B's minorID)
startPoint | bigint
length | bigint
-------------------
What I'm looking to do is get a list of all rows in table 'B', but show how much space is left for each row.
The remaining space can be found by finding the highest "startPoint", adding the value o the "length" column for the row containing the highest "startPoint", then subtracting that combined value from the "totalSize" column in table 'B'
I am currently able to achieve this using the following code:
create table #results (MinorID bigint, MajorID bigint, RemainingSpace bigint)
DECLARE @MinorID bigint
DECLARE @TotalSpace bigint
DECLARE @MajorID bigint
DECLARE cur CURSOR FOR
SELECT MinorID, MajorID, TotalSize FROM B
OPEN cur
FETCH NEXT FROM cur INTO @MinorID,@MajorID, @TotalSpace
WHILE @@FETCH_STATUS = 0
BEGIN
DECLARE @UsedSize bigint
SELECT TOP 1 @UsedSize = StartPoint + [length] FROM C
WHERE MinorID = @MinorID AND MajorID = @MajorID
ORDER BY StartPoint DESC
INSERT INTO #results VALUES (@MinorID,@MajorID,@TotalSpace - @UsedSize)
FETCH NEXT FROM cur INTO @MinorID,@MajorID, @TotalSpace
END
CLOSE cur
DEALLOCATE cur
SELECT * FROM #results
drop table #results
The problem is that I expect these tables are going to get VERY large, and I realise that running a cursor over the tables probably isn't the fastest way to achieve what I want.
However, I'm struggling to find a better solution (Monday morning blues), and was hoping someone more awake / better at SQL than me can suggest a solution!
note: The table designs are not "set in stone", so if the only solution is to denormalize the data so that table 'B' keeps a record of it's "taken space", then I'm open to that...
EDIT:
I went with a modified version of the accepted answer, as follows:
SELECT B.*, coalesce(C.StartPoint + C.Length,0) AS UsedSize
FROM TableB B
LEFT JOIN
(
SELECT *, DENSE_RANK() OVER(PARTITION BY C.MajorID, C.MinorID ORDER BY C.StartPoint DESC) AS Rank
FROM TableC C
) C
ON C.MajorID = B.MajorID
AND C.MinorID = B.MinorID
AND C.Rank = 1