The following is similar to @ Gordon Linoff โs suggestion that it also โdecomposesโ the range list into a list of start and end dates. However, the result list uses a different method. He also assumes that only the start date is included, but the end date is not.
WITH unpivoted AS ( SELECT PropertyId, EventDate, OwnershipPercent, PercentFactor = CASE EventDateType WHEN 'EndDate' THEN -1 ELSE 1 END FROM Ownership UNPIVOT ( EventDate FOR EventDateType IN (StartDate, EndDate) ) u ) , summedup AS ( SELECT DISTINCT PropertyId, EventDate, TotalPercent = SUM(OwnershipPercent * PercentFactor) OVER (PARTITION BY PropertyId ORDER BY EventDate) FROM unpivoted ) SELECT s.EventDate, s.TotalPercent, o.PropertyId, o.PersonId, o.StartDate, o.EndDate, o.OwnershipPercent FROM summedup s INNER JOIN Ownership o ON s.PropertyId = o.PropertyId AND s.EventDate >= o.StartDate AND s.EventDate < o.EndDate WHERE TotalPercent > 100
To explain how this works, I will consider the content of Ownership as follows:
PropertyId PersonId StartDate EndDate OwnershipPercent ---------- -------- ---------- ---------- ---------------- 1 1 2010-01-01 2012-01-01 80 1 2 2011-01-01 2011-03-01 20 1 3 2011-02-01 2011-04-01 10 1 4 2011-05-01 2011-07-01 40
Now you can see that in the first step, independent, not only each row of the source table is replaced by two rows, but also each percentage value is marked as an increment ( PercentFactor = 1 ), and decrement ( PercentFactor = -1 ), depending from whether it comes with a start date or with an end date. So, unpivoted CTE evaluates the following set of results:
PropertyId EventDate OwnershipPercent PercentFactor ---------- ---------- ---------------- ------------- 1 2010-01-01 80 1 1 2011-01-01 20 1 1 2011-02-01 10 1 1 2011-03-01 20 -1 1 2011-04-01 10 -1 1 2011-05-01 40 1 1 2011-07-01 40 -1 1 2012-01-01 80 -1
At this point, the idea is to first calculate the current OwnershipPercent totals for each EventDate for each PropertyId , taking into account whether the value is increasing or decreasing. (In fact, you could include a sign on OwnershipPercent in the first step instead of highlighting a separate PercentFactor column. I chose the latter as a slightly better illustration of the idea, but there should be no penalty for performance if you prefer the first). And this is what you get after calculating the current totals (which is what the second CTE, summedup ):
PropertyId EventDate TotalPercent ---------- ---------- ------------ 1 2010-01-01 80 1 2011-01-01 100 1 2011-02-01 110 1 2011-03-01 90 1 2011-04-01 80 1 2011-05-01 120 1 2011-07-01 80 1 2012-01-01 0
Note, however, that this result set may contain duplicate rows. In particular, this will happen if, for the same PropertyId some ranges start or end at the same time or some range ends exactly at the beginning of the date of another range. That is why you can see the DISTINCT used at this point.
Now that the total percentages on key dates are known, those that do not exceed 100 can simply be filtered out, and the rest join Ownership to access the details of the owners who contribute to the amounts received. So, the main query gives you this as the final result:
EventDate TotalPercent PropertyId PersonId StartDate EndDate OwnershipPercent ---------- ------------ ---------- -------- ---------- ---------- ---------------- 2011-02-01 110 1 1 2010-01-01 2012-01-01 80 2011-02-01 110 1 2 2011-01-01 2011-03-01 20 2011-02-01 110 1 3 2011-02-01 2011-04-01 10 2011-05-01 120 1 1 2010-01-01 2012-01-01 80 2011-05-01 120 1 4 2011-05-01 2011-07-01 40
You can also see (as well as play with) this query in SQL Fiddle .