SQL Server中Oracle的RowID的等价物

78 sql t-sql sql-server row-number rowid

什么相当于SQL Server中的Oracle RowID?

Mar*_*ith 115

来自Oracle文档

ROWID伪列

对于数据库中的每一行,ROWID伪列返回行的地址.Oracle数据库rowid值包含查找行所需的信息:

  • 对象的数据对象编号
  • 行所在的数据文件中的数据块
  • 数据块中行的位置(第一行为0)
  • 行所在的数据文件(第一个文件为1).文件号是相对于表空间的.

SQL Server中与此最接近的是rid具有三个组件File:Page:Slot.

在SQL Server 2008中,可以使用未记录和不受支持的%%physloc%%虚拟列来查看此内容.这将返回一个binary(8)值,其页面ID在前四个字节中,然后是2个字节用于文件ID,后面是2个字节用于页面上的插槽位置.

标量函数sys.fn_PhysLocFormattersys.fn_PhysLocCrackerTVF可用于将其转换为更易读的形式

CREATE TABLE T(X INT);

INSERT INTO T VALUES(1),(2)

SELECT %%physloc%% AS [%%physloc%%],
       sys.fn_PhysLocFormatter(%%physloc%%) AS [File:Page:Slot]
FROM T
Run Code Online (Sandbox Code Playgroud)

示例输出

+--------------------+----------------+
|    %%physloc%%     | File:Page:Slot |
+--------------------+----------------+
| 0x2926020001000000 | (1:140841:0)   |
| 0x2926020001000100 | (1:140841:1)   |
+--------------------+----------------+
Run Code Online (Sandbox Code Playgroud)

请注意,查询处理器不会利用此功能.虽然可以在一个WHERE条款中使用它

SELECT *
FROM T
WHERE %%physloc%% = 0x2926020001000100 
Run Code Online (Sandbox Code Playgroud)

SQL Server 不会直接搜索指定的行.相反,它将执行全表扫描,评估%%physloc%%每一行并返回匹配的行(如果有的话).

要反转前面提到的2个函数执行的过程并获得binary(8)与已知文件,页面,插槽值对应的值,可以使用下面的值.

DECLARE @FileId int = 1,
        @PageId int = 338,
        @Slot   int = 3

SELECT CAST(REVERSE(CAST(@PageId AS BINARY(4))) AS BINARY(4)) +
       CAST(REVERSE(CAST(@FileId AS BINARY(2))) AS BINARY(2)) +
       CAST(REVERSE(CAST(@Slot   AS BINARY(2))) AS BINARY(2))
Run Code Online (Sandbox Code Playgroud)


Xia*_*ofu 9

如果要唯一地标识表中的行而不是结果集,那么您需要查看使用IDENTITY列之类的内容.请参阅SQL Server帮助中的"IDENTITY属性".SQL Server不像Oracle那样为表中的每一行自动生成ID,因此您必须不必创建自己的ID列并在查询中显式获取它.

编辑:对于结果集行的动态编号,请参见下文,但这可能与Oracle的ROWNUM相当,我假设您希望上面的内容在页面上的所有注释中.对于SQL Server 2005及更高版本,您可以使用新的" 排名函数"函数来实现行的动态编号.

例如,我在我的查询中执行此操作:

select row_number() over (order by rn_execution_date asc) as 'Row Number', rn_execution_date as 'Execution Date', count(*) as 'Count'
from td.run
where rn_execution_date >= '2009-05-19'
group by rn_execution_date
order by rn_execution_date asc
Run Code Online (Sandbox Code Playgroud)

会给你:

Row Number  Execution Date           Count
----------  -----------------        -----
1          2009-05-19 00:00:00.000  280
2          2009-05-20 00:00:00.000  269
3          2009-05-21 00:00:00.000  279
Run Code Online (Sandbox Code Playgroud)

关于动态编号行的support.microsoft.com上还有一篇文章.


小智 9

我必须重复一个包含许多列的非常大的表,速度很重要.因此,我使用适用于任何表的此方法:

delete T from 
(select Row_Number() Over(Partition By BINARY_CHECKSUM(*) order by %%physloc%% ) As RowNumber, * From MyTable) T
Where T.RowNumber > 1
Run Code Online (Sandbox Code Playgroud)


Dar*_*mas 8

查看新的ROW_NUMBER函数.它的工作原理如下:

SELECT ROW_NUMBER() OVER (ORDER BY EMPID ASC) AS ROWID, * FROM EMPLOYEE
Run Code Online (Sandbox Code Playgroud)

  • 我认为这是rownum而不是rowid的替代品. (14认同)

小智 6

有几个问题的答案上面会解决缺乏直接引用特定行,但将无法正常工作,如果变化发生在一个表中的其他行.这是我的答案在技术上很短的标准.

Oracle ROWID的一个常见用途是提供一种(某种程度上)稳定的方法来选择行,然后返回到行来处理它(例如,更新它).查找行的方法(复杂连接,全文搜索或逐行浏览以及对数据应用程序测试)可能无法轻松或安全地重新使用以限定UPDATE语句.

SQL Server RID似乎提供相同的功能,但不提供相同的性能.这是我看到的唯一问题,不幸的是,保留ROWID的目的是避免重复昂贵的操作来查找例如非常大的表中的行.尽管如此,许多情况下的表现都是可以接受的.如果Microsoft在将来的版本中调整优化程序,则可以解决性能问题.

也可以简单地使用FOR UPDATE并在程序程序中保持CURSOR打开.然而,这在大型或复杂的批处理中可能证明是昂贵的.

警告:例如,如果SELECT和UPDATE之间的DBA重建数据库,那么即使Oracle的ROWID也不会稳定,因为它是物理行标识符.所以ROWID设备应该只在一个范围很广的任务中使用.


小智 5

如果您想对表中的行进行永久编号,请不要使用 SQL Server 的 RID 解决方案。它的性能比旧 386 上的 Access 差。对于 SQL Server,只需创建一个 IDENTITY 列,并使用该列作为聚集主键。这将在表上放置一个永久、快速的整数 B 树,更重要的是每个非聚集索引将使用它来定位行。如果您尝试像 Oracle 一样在 SQL Server 中进行开发,您将创建一个性能很差的数据库。您需要针对引擎进行优化,而不是假装它是不同的引擎。

另外,请不要使用 NewID() 用 GUID 填充主键,否则会降低插入性能。如果必须使用 GUID,请使用 NewSequentialID() 作为列默认值。但INT仍然会更快。

另一方面,如果您只想对查询结果的行进行编号,请使用 RowNumber Over() 函数作为查询列之一。


Cur*_*son 4

来自http://vyaskn.tripod.com/programming_faq.htm#q17

Oracle 有一个 rownum 来使用行号或行 id 访问表的行。SQL Server 中有类似的东西吗?或者如何在 SQL Server 中生成带有行号的输出?

没有与 SQL Server 中 Oracle 的 rownum 或 row id 直接等效的东西。严格来说,在关系数据库中,表中的行没有排序,行 ID 没有任何意义。但如果您需要该功能,请考虑以下三种替代方案:

  • IDENTITY在表中添加一列。

  • 使用以下查询为每行生成行号。以下查询为 pubs 数据库的authors 表中的每一行生成行号。为了使该查询正常工作,表必须具有唯一键。

    SELECT (SELECT COUNT(i.au_id) 
            FROM pubs..authors i 
            WHERE i.au_id >= o.au_id ) AS RowID, 
           au_fname + ' ' + au_lname AS 'Author name'
    FROM          pubs..authors o
    ORDER BY      RowID
    
    Run Code Online (Sandbox Code Playgroud)
  • 使用临时表方法,将整个结果集以及函数生成的行 ID 存储到临时表中IDENTITY() 。创建临时表的成本很高,尤其是在使用大型表时。如果您的表中没有唯一的键,请采用这种方法。