我有一些 SQL 表,比如单列 c1:
c1 |
---|
10 |
3 |
1 |
10 |
5 |
现在,我想发出一个 SQL 命令(不是我的 DBMS 的某些操作,我故意没有提到),这导致我的表是:
c1 | 记录索引 |
---|---|
10 | 0 |
3 | 1 |
1 | 2 |
10 | 3 |
5 | 4 |
很简单……这可以吗?显然,你事先并不知道表的长度,所以没有 SQL 插入或类似的技巧。
注意:我想要一个一般性的答案,但要具体一点 - 我正在使用MonetDB。
关系数据库中没有“行索引”之类的东西(请注意,关系数据库包含行,而不是“记录”),但是如果您可以找到用于对结果进行排序的列,则可以使用窗口功能:
select c1,
row_number() over (order by some_column) as record_index
from the_table
order by record_index;
(你没有指定你的DBMS,上面是ANSI SQL)
编辑
如果您没有要排序的列,则可以尝试按常量值排序,这将带回“无序”的行:
select record_index,
row_number() over (order by 42) as record_index
from the_table
order by record_index;
但同样:没有“自然”的行顺序。磁盘上可能有一个,但很可能不是在检索期间使用的那个 - 特别是当表没有聚集索引时(Oracle 默认不使用聚集索引,Postgres 没有它们完全)。
在检索数据时,DBMS 也可能会应用额外的优化。Oracle、Postgres 和我相信 SQL Server 也可以例如“跳跃”来自不同会话的表扫描,以优化从磁盘的物理读取。在这种情况下,即使硬盘上的物理布局没有改变,两个并发选择也会显示不同的“顺序”。
然后由于更新而对物理存储进行了更改(例如,如果一行不再适合块,因为它的大小增加了)。
受@a_horse_with_no_name 的回答启发...:
SELECT
c1,
row_number() OVER (ORDER BY dummy)-1 AS record_index
FROM
(SELECT
c1,
42 AS dummy
FROM t1
) AS t1_augmented;
(当然要注意 row_number() 的结果是从 1 开始的。)