Вот основанный на множестве подход к решению этой проблемы.Обратите внимание, что первый CTE не нужен, если в вашей базе данных уже есть таблица Numbers
:
declare @t table (ID int,GMD decimal(5,2),IsPinned bit)
insert into @t (ID,GMD,IsPinned) values
(1,2.5,0), (2, 0 ,1), (3, 2 ,0), (4, 4 ,1), (5, 3 ,0)
;With Numbers as (
select ROW_NUMBER() OVER (ORDER BY ID) n from @t
), NumbersWithout as (
select
n,
ROW_NUMBER() OVER (ORDER BY n) as rn
from
Numbers
where n not in (select ID from @t where IsPinned=1)
), DataWithout as (
select
*,
ROW_NUMBER() OVER (ORDER BY GMD desc) as rn
from
@t
where
IsPinned = 0
)
select
t.*,
COALESCE(nw.n,t.ID) as RowNo
from
@t t
left join
DataWithout dw
inner join
NumbersWithout nw
on
dw.rn = nw.rn
on
dw.ID = t.ID
order by COALESCE(nw.n,t.ID)
Надеюсь, мое наименование прояснит, что мы делаем.Я немного дерзкий в последнем SELECT
, используя COALESCE
, чтобы получить окончательный RowNo
, когда вы, возможно, ожидали выражение CASE
.Но это работает, потому что содержимое DataWithout
CTE определено так, что оно существует только для неподкрепленных элементов, что приводит к сбою окончательного LEFT JOIN
.
Результаты:
ID GMD IsPinned RowNo
----------- --------------------------------------- -------- --------------------
5 3.00 0 1
2 0.00 1 2
1 2.50 0 3
4 4.00 1 4
3 2.00 0 5
Секундавариант, который может работать лучше (но никогда не предполагать, всегда тестировать):
declare @t table (ID int,GMD decimal(5,2),IsPinned bit)
insert into @t (ID,GMD,IsPinned) values
(1,2.5,0), (2, 0 ,1), (3, 2 ,0), (4, 4 ,1), (5, 3 ,0)
;With Numbers as (
select ROW_NUMBER() OVER (ORDER BY ID) n from @t
), NumbersWithout as (
select
n,
ROW_NUMBER() OVER (ORDER BY n) as rn
from
Numbers
where n not in (select ID from @t where IsPinned=1)
), DataPartitioned as (
select
*,
ROW_NUMBER() OVER (PARTITION BY IsPinned ORDER BY GMD desc) as rn
from
@t
)
select
dp.ID,dp.GMD,dp.IsPinned,
CASE WHEN IsPinned = 1 THEN ID ELSE nw.n END as RowNo
from
DataPartitioned dp
left join
NumbersWithout nw
on
dp.rn = nw.rn
order by RowNo
В третьем CTE, введя PARTITION BY
и удалив предложение WHERE
, мы гарантируем, что у нас есть все строки данных, так чтонам не нужно повторно присоединяться к исходной таблице в конечном результате в этом варианте.