I went with a CTE-based approach where, hopefully, each step shows the thinking process that I followed:
declare @t table (Id int not null, Priority varchar(6) not null) insert into @t (Id,Priority) values (1,'High'), (2,'High'), (3,'High'), (4,'High'), (5,'Medium'), (6,'Low'), (7,'Low') --We want 6 rows. We'd like to get 1 low, if available, and 2 mediums, if available ; with NumberedRows as ( select Id,Priority, ROW_NUMBER() OVER (PARTITION BY Priority ORDER BY Id) as rn, CASE Priority WHEN 'High' then 1 WHEN 'Medium' THEN 2 ELSE 3 END as NumPri from @t ), Selection as ( select Id, Priority, NumPri, CASE WHEN NumPri = 3 and rn <= 1 THEN 1 WHEN NumPri = 2 and rn <= 2 THEN 2 WHEN NumPri = 1 THEN 3 WHEN NumPri = 2 THEN 4 ELSE 5 --Low, rn>1 END as Preference from NumberedRows ), Chosen as ( select top 6 * from Selection order by Preference ) select * from Chosen order by NumPri,Id
(Note that the sample data at the top of my code takes as much formatting as the table in your question, but it can really be used in a script)
If the number of items to select changes, you will need to change:
WHEN NumPri = 3 and rn <= 1 THEN 1 WHEN NumPri = 2 and rn <= 2 THEN 2
(Change rn values) and:
select top 6 * from Selection order by Preference
(Change it if you want, how much is required)
Please also note that it doesn’t matter that you say you want 3 items with high priority - it doesn’t matter, since items with high priority are used as fillers if not enough low priority values can be located.