T-SQL переставить значения из 1 ... n - PullRequest
1 голос
/ 24 марта 2019

Мне нужно переставить ранговые числа, в настоящее время они имеют пробелы, такие как 1, 12, 13, 20, которые мне нужно переставить с 1,2,3,4 enter image description here

после моего решения оно переставляется, но я считаю, что должна быть намного более короткая версия для перестановки.

Вот что я пробовал:

if object_id('tempdb..#rank') is not null drop table #rank
if object_id('tempdb..#rank2') is not null drop table #rank2

select driver_id, zone_name, zone_rank, 0 as updated into #rank from driver_login where zone_name = 'Out of Zone' order by zone_rank 
select * into #rank2 from #rank

select * from #rank2 order by zone_rank

declare @currentRank int
declare @driverId int

while exists(select 1 from #rank2)
begin
    set @currentRank = (select min(zone_rank) from #rank2)
    set @driverId = (select driver_id from #rank2 where zone_rank = @currentRank)

    if(@currentRank != 1 and exists(select 1 from #rank where zone_rank = 1))
    begin
     declare @minRank int = (select max(zone_rank) from #rank where updated = 1)
     update #rank set zone_rank = @minRank + 1, updated = 1 where driver_id = @driverId
    end
    else if(@currentRank != 1 and not exists(select 1 from #rank where zone_rank = 1))
    begin
     update #rank set zone_Rank = 1, updated = 1 where driver_id = @driverId
    end


    delete from #rank2 where driver_id = @driverId
end

select * from #rank order by zone_rank

Вот вывод моего кода: enter image description here

Ответы [ 3 ]

1 голос
/ 24 марта 2019

В SQL Server 2008 вы можете использовать функции ранжирования и один из следующих операторов:

-- Table
CREATE TABLE driver_login (
   driver_id int, 
   zone_name varchar(20), 
   zone_rank int
)
INSERT INTO driver_login
   (driver_id, zone_name, zone_rank)
VALUES
   (100, 'Out of Zone', 5),
   (113, 'Out of Zone', 10),
   (101, 'Out of Zone', 12),
   (114, 'Out of Zone', 13)

-- SELECT statement
SELECT 
   driver_id, 
   zone_name, 
   RANK() OVER (PARTITION BY zone_name ORDER BY zone_rank) zone_rank, 
   1 as updated 
INTO #rank 
FROM driver_login
WHERE zone_name = 'Out of Zone' 

SELECT *
FROM #rank

-- UPDATE statement
;WITH UpdateCTE AS (
   SELECT 
      driver_id, 
      zone_name,
      zone_rank,
      RANK() OVER (PARTITION BY zone_name ORDER BY zone_rank) AS RankID
   FROM driver_login
   WHERE zone_name = 'Out of Zone' 
) 
UPDATE UpdateCTE
SET zone_rank = RankID

SELECT *
FROM driver_login
0 голосов
/ 24 марта 2019

Используйте обновляемый CTE:

with toupdate as (
      select dl.*,
             row_number() over (order by zone_rank) as new_zone_rank
      from driver_login dl
     )
    set zone_rank = new_zone_rank,
        updated = 1
    where zone_rank <> new_zone_rank;
0 голосов
/ 24 марта 2019

Попробуйте использовать функцию RANK:

Возвращает ранг каждой строки в разделе набора результатов. ранг строки равен одному плюс количество рангов, предшествующих строке под вопросом.

ROW_NUMBER и RANK похожи. ROW_NUMBER нумерует все строки последовательно (например, 1, 2, 3, 4, 5). RANK обеспечивает то же самое числовое значение для связей (например, 1, 2, 2, 4, 5).

У вас будет что-то вроде этого:

WITH CTE AS
(
    SELECT driver_id,
        RANK() OVER(ORDER BY driver_id) AS RN
    FROM #rank
)
UPDATE #rank
SET zone_rank = RN
FROM #rank INNER JOIN
    CTE ON YourTable.driver_id = CTE.driver_id
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...