在sql行中填充序列

发布于 2024-10-15 09:51:44 字数 704 浏览 4 评论 0原文

我有一个表,用于存储一组属性并使它们按顺序排列。有可能从表中删除其中一个属性(行),并且应该压缩位置序列。

例如,如果我最初有这些值集:

+----+--------+-----+
| 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 的示例,因为系统应该支持这两种引擎。谢谢!

更新:原因是用户可以随意修改位置,以及添加或删除新行。位置向用户显示,因此,这些位置应始终显示一致的序列(并且该序列必须存储,而不是按需生成)。

I have a table that stores a group of attributes and keeps them ordered in a sequence. The chance exists that one of the attributes (rows) could be deleted from the table, and the sequence of positions should be compacted.

For instance, if I originally have these set of values:

+----+--------+-----+
| id | name   | pos |
+----+--------+-----+
|  1 | one    |   1 |
|  2 | two    |   2 |
|  3 | three  |   3 |
|  4 | four   |   4 |
+----+--------+-----+

And the second row was deleted, the position of all subsequent rows should be updated to close the gaps. The result should be this:

+----+--------+-----+
| id | name   | pos |
+----+--------+-----+
|  1 | one    |   1 |
|  3 | three  |   2 |
|  4 | four   |   3 |
+----+--------+-----+

Is there a way to do this update in a single query? How could I do this?

PS: I'd appreciate examples for both SQLServer and Oracle, since the system is supposed to support both engines. Thanks!

UPDATE: The reason for this is that users are allowed to modify the positions at will, as well as adding or deleting new rows. Positions are shown to the user, and for that reason, these should show a consistence sequence at all times (and this sequence must be stored, and not generated on demand).

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

追风人 2024-10-22 09:51:44

不确定它是否有效,但对于 Oracle 我会尝试以下操作:

update my_table set pos = rownum;

Not sure it works, But with Oracle I would try the following:

update my_table set pos = rownum;
时光清浅 2024-10-22 09:51:44

这可行,但对于大型数据集可能不是最佳的:

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

this would work but may be suboptimal for large datasets:

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
遮云壑 2024-10-22 09:51:44

您真的需要序列值是连续的,还是只需要能够显示连续值?最简单的方法是让实际序列变得稀疏,并根据顺序计算排名:(

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 |
+----+--------+-----+

这不起作用的唯一原因是用户直接在数据库中编辑数据。不过,即使在这种情况下,我也倾向于通过视图和替代触发器来使用这种解决方案。

Do you really need the sequence values to be contiguous, or do you just need to be able to display the contiguous values? The easiest way to do this is to let the actual sequence become sparse and calculate the rank based on the order:

select id, 
       name, 
       dense_rank() over (order by pos) as pos,
       pos as sparse_pos 
from my_table

(note: this is an Oracle-specific query)

If you make the position sparse in the first place, this would even make re-ordering easier, since you could make each new position halfway between the two existing ones. For instance, if you had a table like this:

+----+--------+-----+
| id | name   | pos |
+----+--------+-----+
|  1 | one    | 100 |
|  2 | two    | 200 |
|  3 | three  | 300 |
|  4 | four   | 400 |
+----+--------+-----+

When it becomes time to move ID 4 into position 2, you'd just change the position to 150.


Further explanation:

Using the above example, the user initially sees the following (because you're masking the position):

+----+--------+-----+
| id | name   | pos |
+----+--------+-----+
|  1 | one    |   1 |
|  2 | two    |   2 |
|  3 | three  |   3 |
|  4 | four   |   4 |
+----+--------+-----+

When the user, through your interface, indicates that the record in position 4 needs to be moved to position 2, you update the position of ID 4 to 150, then re-run your query. The user sees this:

+----+--------+-----+
| id | name   | pos |
+----+--------+-----+
|  1 | one    |   1 |
|  4 | four   |   2 |
|  2 | two    |   3 |
|  3 | three  |   4 |
+----+--------+-----+

The only reason this wouldn't work is if the user is editing the data directly in the database. Though, even in that case, I'd be inclined to use this kind of solution, via views and instead-of triggers.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文