根据 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
【问题讨论】:
你真的有两张桌子 -productproperty
和 MyTable
还是同一张桌子?
对不起,我更正了。我只有一张桌子。
那你肯定最好不要加入答案,我认为这将是最简单和最快的一个
与其坚持使用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】:如果productproperty
和MyTable
真的是同一张桌子,我会这样做:
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() 更新列的主要内容,如果未能解决你的问题,请参考以下文章
分组 根据某一列进行排序,根据shopid分组,用createTime排序,返回row_number()序号 select no =row_number() over (partition by s
Postgresql 根据单列或几列分组去重row_number() over() partition by
通过 row_number() 使用 over order 更新