T-SQL 重新排列 1...n 的值
T-SQL Rearrange the values from 1...n
我需要重新排列排名数字,目前它们有 1、12、13、20 等差距,我需要从 1、2、3、4
重新排列
在我的解决方案之后,它正在重新排列,但我相信必须有很多更短的版本来重新排列。
这是我尝试过的:
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
这是我的代码的输出:
从 SQL Server 2008 开始,您可以使用 ranking functions 和以下语句之一:
-- 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
尝试使用 RANK
函数:
Returns the rank of each row within the partition of a result set. The
rank of a row is one plus the number of ranks that come before the row
in question.
ROW_NUMBER and RANK are similar. ROW_NUMBER numbers all rows
sequentially (for example 1, 2, 3, 4, 5). RANK provides the same
numeric value for ties (for example 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
使用可更新的 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;
我需要重新排列排名数字,目前它们有 1、12、13、20 等差距,我需要从 1、2、3、4
在我的解决方案之后,它正在重新排列,但我相信必须有很多更短的版本来重新排列。
这是我尝试过的:
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
这是我的代码的输出:
从 SQL Server 2008 开始,您可以使用 ranking functions 和以下语句之一:
-- 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
尝试使用 RANK
函数:
Returns the rank of each row within the partition of a result set. The rank of a row is one plus the number of ranks that come before the row in question.
ROW_NUMBER and RANK are similar. ROW_NUMBER numbers all rows sequentially (for example 1, 2, 3, 4, 5). RANK provides the same numeric value for ties (for example 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
使用可更新的 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;