我有一个存储一组属性的表,并按顺序对它们进行排序。存在这样的可能性:可以从表中删除其中一个属性(行),并且应该压缩位置序列。
例如,如果我最初拥有这些值集:
+----+--------+-----+
| id | name | pos |
+----+--------+-----+
| 1 | one | 1 |
| 2 | two | 2 |
| 3 | three | 3 |
| 4 | four | 4 |
+----+--------+-----+
第二行被删除,所有后续行的位置应该更新以填补空白。结果应该是这样的:
+----+--------+-----+
| id | name | pos |
+----+--------+-----+
| 1 | one | 1 |
| 3 | three | 2 |
| 4 | four | 3 |
+----+--------+-----+
有没有办法在单个查询中执行此更新?我怎么能这样做?
PS:我很欣赏SQLServer和Oracle的例子,因为系统应该支持两个引擎。谢谢!
更新:原因是允许用户随意修改位置,以及添加或删除新行。位置显示给用户,因此,这些位置应始终显示一致性序列(此序列必须存储,而不是按需生成)。
答案 0 :(得分:4)
不确定是否有效,但对于Oracle,我会尝试以下方法:
update my_table set pos = rownum;
答案 1 :(得分:0)
这可行,但对于大型数据集可能不是最理想的:
SQL> UPDATE my_table t
2 SET pos = (SELECT COUNT(*) FROM my_table WHERE id <= t.id);
3 rows updated
SQL> select * from my_table;
ID NAME POS
---------- ---------- ----------
1 one 1
3 three 2
4 four 3
答案 2 :(得分:0)
您真的需要序列值是连续的,还是只需要能够显示连续的值?最简单的方法是让实际序列变得稀疏,并根据顺序计算排名:
select id,
name,
dense_rank() over (order by pos) as pos,
pos as sparse_pos
from my_table
(注意:这是特定于Oracle的查询)
如果你首先使位置稀疏,这甚至会使重新排序变得更容易,因为你可以将每个新位置放在两个现有位置的中间位置。例如,如果您有一个这样的表:
+----+--------+-----+
| id | name | pos |
+----+--------+-----+
| 1 | one | 100 |
| 2 | two | 200 |
| 3 | three | 300 |
| 4 | four | 400 |
+----+--------+-----+
当将ID 4移动到位置2时,您只需将位置更改为150。
进一步解释:
使用上面的示例,用户最初会看到以下内容(因为您正在屏蔽该位置):
+----+--------+-----+
| id | name | pos |
+----+--------+-----+
| 1 | one | 1 |
| 2 | two | 2 |
| 3 | three | 3 |
| 4 | four | 4 |
+----+--------+-----+
当用户通过您的界面指示位置4中的记录需要移动到位置2时,您将ID 4的位置更新为150,然后重新运行查询。用户看到了这一点:
+----+--------+-----+
| id | name | pos |
+----+--------+-----+
| 1 | one | 1 |
| 4 | four | 2 |
| 2 | two | 3 |
| 3 | three | 4 |
+----+--------+-----+
这不起作用的唯一原因是用户是否直接在数据库中编辑数据。虽然,即使在这种情况下,我也倾向于使用这种解决方案,通过视图和替代触发器。