根据 row_number() 更新列

Posted

技术标签:

【中文标题】根据 row_number() 更新列【英文标题】:Update a column based on row_number() 【发布时间】:2015-08-10 21:09:39 【问题描述】:

我为我的表创建了一个默认值为 0 的新非空列,它保持显示顺序。我想更新该表的所有行,该 displayorder 的值 row_number() 超过 id 排序。在这里,我可以为一个 id 做到这一点。我怎样才能为所有 id 做到这一点。

我的桌子是:

id | personid | name   | displayorder
---+----------+--------+------------
 1 |    10    | test1  |    0
 2 |    10    | test2  |    0
 3 |    10    | test3  |    0
 4 |    10    | test4  |    0
 5 |    10    | test5  |    0
 6 |    11    | test6  |    0
 7 |    11    | test7  |    0
 8 |    12    | test8  |    0

我想要的结果是:

id | personid | name   | displayorder
---+----------+--------+------------
 1 |    10    | test1  |    1
 2 |    10    | test2  |    2
 3 |    10    | test3  |    3
 4 |    10    | test4  |    4
 5 |    10    | test5  |    5
 6 |    11    | test6  |    1
 7 |    11    | test7  |    2
 8 |    12    | test8  |    1

这是我的 sql 代码,但它只适用于一个给定的 id:

update MyTable
set displayorder = z.ord
 FROM  (
   SELECT row_number() over (order by id) as ord, id 
     FROM MyTable p2
   where p2.personid = 1
   ) z
  where MyTable.id= z.id
  and personid = 1

【问题讨论】:

你真的有两张桌子 - productpropertyMyTable 还是同一张桌子? 对不起,我更正了。我只有一张桌子。 那你肯定最好不要加入答案,我认为这将是最简单和最快的一个 与其坚持使用SQL,不如切换到T-SQL并利用循环能力。 ...或者,根本不使用 displayorder 列并即时创建订单。我无法想象您为维护列上的数据完整性而付出的努力。只是我的 2 美分。 【参考方案1】:

使用此代码:

 Create  TABLE #order
    (
        Id INT,
        PersonId INT,
        Name NVARCHAR(25),
        DisplayOrder INT
    )

    INSERT INTO #ORDER VALUES(1 , 10 , 'test1',0 )
    INSERT INTO #ORDER VALUES(2 , 10 , 'test2',0 )
    INSERT INTO #ORDER VALUES(3 , 10 , 'test3',0 )
    INSERT INTO #ORDER VALUES(4 , 10 , 'test4',0 )
    INSERT INTO #ORDER VALUES(5 , 10 , 'test5',0 )
    INSERT INTO #ORDER VALUES(6 , 11 , 'test6',0 )
    INSERT INTO #ORDER VALUES(7 , 11 , 'test7',0 )
    INSERT INTO #ORDER VALUES(8 , 12 , 'test8',0 )



 update #order 
    Set #order.DisplayOrder=R.DisplayOrder
    from(select id,ROW_NUMBER() over (partition by S.personid  order by S.id) as DisplayOrder
    from #order S) R
    where #order.Id=R.id

    select * from #order

【讨论】:

谢谢它的工作。我刚刚了解了“partition by”,谢谢。 感谢 Can 很好地解释了我的问题,并感谢 Hell Boy 的漂亮而简单的灵魂!【参考方案2】:

如果productpropertyMyTable 真的是同一张桌子,我会这样做:

with cte as (
    select
        t.displayorder,
        row_number() over(partition by t.PersonId order by t.Id) as rn
    from MyTable as t
)
update cte set displayorder = rn

这个使用了公共表表达式在 SQL Server 中被视为可更新视图这一事实。

甚至可以使用row_number() 作为显示顺序创建视图,这样会自动重新计算,因此您不必每次添加/删除行时都更新表格。

【讨论】:

@Roman Pekar 答案的美妙之处在于不需要主键并且仍然使用一个表。【参考方案3】:

一个快速的解决方案是使用排名工具。该示例应该满足您的要求。

DECLARE @Pid TABLE
(
    Id INT,
    PersonId INT,
    Name NVARCHAR(25),
    DisplayOrder INT
)

INSERT INTO @Pid
VALUES
(1 , 10 , 'test1',0 ),
(2 , 10 , 'test2',0 ),
(3 , 10 , 'test3',0 ),
(4 , 10 , 'test4',0 ),
(5 , 10 , 'test5',0 ),
(6 , 11 , 'test6',0 ),
(7 , 11 , 'test7',0 ),
(8 , 12 , 'test8',0 )

UPDATE pid
SET DisplayOrder = dpid.rank
FROM @Pid pid
INNER JOIN 
(
    SELECT *, Rank() OVER(Partition by PersonId Order by Id) as rank
    FROM @Pid
 )dpid ON dpid.Id = pid.Id

 SELECT * 
 FROM @Pid

【讨论】:

原来的问题有 2 张桌子,而你只有一张。我 90% 确定应该只有一张桌子,但我会等待主题启动评论 我认为如果 OP 通过 ID 加入,它是一个还是 2 个表都没有关系(我希望不是,但你永远不知道)。只需更改上面示例中的更新语句即可更新第二个表。

以上是关于根据 row_number() 更新列的主要内容,如果未能解决你的问题,请参考以下文章

SQL Row_Number() 不排序日期

分组 根据某一列进行排序,根据shopid分组,用createTime排序,返回row_number()序号 select no =row_number() over (partition by s

Postgresql 根据单列或几列分组去重row_number() over() partition by

通过 row_number() 使用 over order 更新

如何使用 ROW_NUMBER() 在 SELECT 中获取增量“RowId”列

浅谈ROW_NUMBER() OVER()函数的使用