A seek instead of a scan is possible:
SELECT *
FROM Periods
WHERE
PeriodYear BETWEEN Year(@startdate) AND Year(@enddate)
AND PeriodYear * 4 + PeriodQuarter
BETWEEN Year(@startdate) * 4 + DATEPART(Quarter, @startdate)
AND Year(@startdate) * 4 + DATEPART(Quarter, @enddate)
Explanation:
I'm composing a new, scaled integer from two component pieces, the year and the quarter, treating each combination of year and quarter as a single number.
Imagine instead that I had done it this way:
AND PeriodYear + (PeriodQuarter - 1) / 4.0
BETWEEN Year(@startdate) + (DATEPART(Quarter, @startdate) - 1) / 4.0
AND Year(@startdate) + (DATEPART(Quarter, @enddate) - 1) / 4.0
Calling my original expression "Mult" and this new one "Div", here are some years and quarters and what those expressions will evaluate to:
Year Qtr Div Mult
2009 1 2009.00 8037
2009 2 2009.25 8038
2009 3 2009.50 8039
2009 4 2009.75 8040
2010 1 2010.00 8041
2010 2 2010.25 8042
2010 3 2010.50 8043
So now if we run a WHERE clause against these rows:
WHERE Div BETWEEN 2009.25 AND 2010.00
You can see how it will return the correct rows. The Mult version really does exactly the same, just scaling the year up instead of the quarter down. The reason I used it is because integer math and multiplication are faster than fractional math and division.
The reason that I use two conditions starting with just the year is to make the query sargable. We want to do the seek based on just year, which isn't possible if we're multiplying it by 4 or doing other math on it. So we get the scan into only the right years first, then fine tune it to eliminate any quarters that shouldn't be in the result.
Another option is to add a calculated column and put an index on it. This wouldn't require any changes to code inserting or updating (as long as they properly use column lists), but would let you do regular range math as you desire.