Using the COUNT aggregate,
you can first count how many rows there are and store in a variable called @cnt. Then
you can compute parameters for the OFFSET-FETCH filter to specify, based on qty ordering,
how many rows to skip (offset value) and how many to filter (fetch value).
The number of rows
to skip is (@cnt - 1) / 2. It’s clear that for an odd count this calculation is correct because you
first subtract 1 for the single middle value, before you divide by 2.
This also works correctly for an even count because the division used in the expression is
integer division; so, when subtracting 1 from an even count, you’re left with an odd value.
When dividing that odd value by 2, the fraction part of the result (.5) is truncated. The number
of rows to fetch is 2 - (@cnt % 2). The idea is that when the count is odd the result of the
modulo operation is 1, and you need to fetch 1 row. When the count is even the result of the
modulo operation is 0, and you need to fetch 2 rows. By subtracting the 1 or 0 result of the
modulo operation from 2, you get the desired 1 or 2, respectively. Finally, to compute the
median quantity, take the one or two result quantities, and apply an average after converting
the input integer value to a numeric one as follows:
DECLARE @cnt AS INT = (SELECT COUNT(*) FROM [Sales].[production].[stocks]);
SELECT AVG(1.0 * quantity) AS median
FROM ( SELECT quantity
FROM [Sales].[production].[stocks]
ORDER BY quantity
OFFSET (@cnt - 1) / 2 ROWS FETCH NEXT 2 - @cnt % 2 ROWS ONLY ) AS D;