В SQL Server это можно сделать с помощью вложенных подзапросов и предложений top
:
select top (@n) *
from (
-- Retrieve @y rows from the special genre
-- The prio field is used to ensure all these rows make it inside @n
select top (@y) 1 as prio, genreid, questionid
from @t
where genreid = @the_one
-- And up to @x rows per non-special genre
union all
select 2 as prio, genreid, questionid
from (
select *
, row_number() over (partition by genreid
order by newid()) as rownr
from @t
where genreid <> @the_one
) sub
where rownr < @x
) sub2
order by
prio, newid()
Пример данных:
declare @t table (id int identity, QuestionId int, GenreId int)
insert @t (GenreId, QuestionId) values
(1,1),
(2,1),(2,1),
(3,1),(3,1),(3,1),
(4,1),(4,1),(4,1),(4,1),
(5,1),(5,1),(5,1),(5,1),(5,1)
declare @n int
declare @x int
declare @y int
declare @the_one int
set @n = 7 -- Total rows
set @x = 3 -- With less then 3 per genre
set @y = 3 -- Except three rows from genre @the_one
set @the_one = 3
Результаты в (один пример, выходные данные отличаются при каждом запуске:
prio genreid questionid
1 3 1
1 3 3
1 3 2
2 4 1
2 1 1
2 5 1
2 5 4