【问题标题】:Dynamically reorder column values in a SQL Server table动态重新排序 SQL Server 表中的列值
【发布时间】:2019-11-01 12:54:20
【问题描述】:

我有一个用于用户技能的 SQL Server 表,每个用户的优先级顺序如下:

+----+------+----------+----------+
| ID | user | skill    | priority |
+----+------+----------+----------+
| 1  | foo  | swimming | 1        |
+----+------+----------+----------+
| 2  | foo  | running  | 2        |
+----+------+----------+----------+
| 3  | foo  | hunting  | 3        |
+----+------+----------+----------+
| 4  | boo  | swimming | 1        |
+----+------+----------+----------+
| 5  | moo  | swimming | 1        |
+----+------+----------+----------+
| 6  | moo  | running  | 2        |
+----+------+----------+----------+

当某个技能的优先级值发生更改时,我如何编写 SQL 代码来重新排序用户所有技能的优先级列值(整数)?

例如:对于用户“foo”,我将“游泳”技能的优先级从(1)更改为(2);更新语句还必须以动态方式更改该用户所有其他技能的优先级。

因此,在该示例中,“游泳”的优先级为 (2) 而不是 (1),跑步的优先级为 (1) 而不是 (2),其他保持不变。

【问题讨论】:

  • 其他一些示例会有所帮助,尤其是对于边缘情况。例如:如果 foo/swimming 的优先级更改为 0,那么 foo/running 是否应该为 1?如果 foo/swimming 改为 5 会怎样?
  • SQL Server 不按任何特定顺序存储或检索项目。查询是使用微处理器中的不同内核并行完成的,因此您必须始终使用 OrderBy 来对结果进行排序。
  • @jdweng,这个问题与存储或检索行的顺序没有任何关系。这是关于为用户的每一行分配新的优先级值,只要该用户的优先级值之一发生更改。
  • @HABO,第一个答案涉及删除行后的重新排序。这个问题是关于简单的重新排序(不删除行)。
  • @HABO,至于您链接的第二个答案,SQL 代码真的很长、很复杂,而且通常很讨厌。我什至不确定它是否正确。

标签: tsql sql-server-2017


【解决方案1】:

在这个答案中,我假设您想在 SQL 中执行此操作,而不是在 C# 中。基于该假设,单个事务中的这两条 SQL 语句指定技能的优先级提高 1。

'Set @User to the required user and @Skill to the required skill.

'Decrease the priority of the user's skill above the specified skill.
UPDATE MyTable
SET    priority = priority + 1
WHERE  user = @User 
AND    priority = (SELECT priority - 1 
                   FROM MyTable 
                   WHERE user = @User
                   AND skill = @Skill)

'Increase the specified skill's priority.
UPDATE MyTable
SET    priority = priority - 1
WHERE  user = @User
AND    skill = @Skill
AND    priority > 1

以类似的方式,这两条SQL语句将指定技能提高到指定优先级。

'Set @User to the required user and @Skill to the required skill.
'Set @NewPriority to the new priority.

'Decrease the higher-prioritised skills.
UPDATE MyTable
SET    priority = priority + 1
WHERE  user = @User 
AND    priority >= @NewPriority 
AND    priority < (SELECT priority
                   FROM MyTable 
                   WHERE user = @User
                   AND skill = @Skill)

'Set the specified skill's priority as requested.
UPDATE MyTable
SET    priority = @NewPriority 
WHERE  user = @User
AND    skill = @Skill
AND    priority > 1

而这三个SQL语句移动指定技能到指定优先级。

'Set @User to the required user and @Skill to the required skill.
'Set @NewPriority to the new priority.

'Decrease the higher-prioritised skills to
'handle case where new priority is higher.
UPDATE MyTable
SET    priority = priority + 1
WHERE  user = @User 
AND    priority >= @NewPriority 
AND    priority < (SELECT priority
                   FROM MyTable 
                   WHERE user = @User
                   AND skill = @Skill)

'Increase the lower-prioritised skills to
'handle case where new priority is lower.
UPDATE MyTable
SET    priority = priority - 1
WHERE  user = @User 
AND    priority <= @NewPriority 
AND    priority > (SELECT priority
                   FROM MyTable 
                   WHERE user = @User
                   AND skill = @Skill)    

'Set the specified skill's priority as requested.
UPDATE MyTable
SET    priority = @NewPriority 
WHERE  user = @User
AND    skill = @Skill

【讨论】:

  • 似乎(在进一步澄清问题 cmets 之后)OP 希望能够将一项技能的优先级更新到用户拥有“n”的 1-n 范围内的任何位置技能。然后根据需要向上或向下调整所有其他技能的优先级,以填充该范围 1-n 中的其余值。
  • @Richard,我添加了代码来满足这个要求。
  • @RoadWarrior 根据我对您的代码的理解,我应该在存储过程中使用最后一部分(三个语句),因为它替换了前两个部分中的旧答案?
  • @Sherif,如果您想将技能重新分配到任何位置,这是正确的(与我在前两个代码部分中提到的其他更简单的用例相反)。
  • @SherifRiad 如果您想让操作原子化,请注意“单个事务中的 SQL 语句”。
猜你喜欢
  • 1970-01-01
  • 2020-01-15
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-07-10
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多