94

什么是 SQL Server 中 Oracle 的 RowID 的等价物?

4

13 回答 13

124

来自 Oracle 文档

ROWID 伪列

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

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

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

在 SQL Server 2008 中,可以使用未记录且不受支持的%%physloc%%虚拟列来查看这一点。这将返回一个binary(8)值,其中前四个字节中的页面 ID,然后是文件 ID 的 2 个字节,然后是页面上的插槽位置的 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

示例输出

+--------------------+----------------+
|    %%physloc%%     | File:Page:Slot |
+--------------------+----------------+
| 0x2926020001000000 | (1:140841:0)   |
| 0x2926020001000100 | (1:140841:1)   |
+--------------------+----------------+

请注意,查询处理器不会利用这一点。虽然可以WHERE在子句中使用 this

SELECT *
FROM T
WHERE %%physloc%% = 0x2926020001000100 

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

要反转前面提到的 2 个函数执行的过程并获取binary(8)与已知 File、Page、Slot 值对应的值,可以使用以下值。

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))
于 2011-09-24T09:17:29.270 回答
16

我必须对包含许多列的非常大的表进行重复数据删除,并且速度很重要。因此,我使用适用于任何表的这种方法:

delete T from 
(select Row_Number() Over(Partition By BINARY_CHECKSUM(*) order by %%physloc%% ) As RowNumber, * From MyTable) T
Where T.RowNumber > 1
于 2016-11-10T19:16:09.500 回答
9

如果您想唯一标识表中的一行而不是您的结果集,那么您需要考虑使用类似 IDENTITY 列的东西。请参阅 SQL Server 帮助中的“IDENTITY 属性”。SQL Server 不会像 Oracle 那样为表中的每一行自动生成 ID,因此您必须费心创建自己的 ID 列并在查询中显式获取它。

编辑:对于结果集行的动态编号,请参见下文,但这可能与 Oracle 的 ROWNUM 等效,我从页面上的所有评论中假设您想要上面的内容。对于 SQL Server 2005 及更高版本,您可以使用新的Ranking Functions函数来实现行的动态编号。

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

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

会给你:

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

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

于 2009-05-26T06:30:25.817 回答
8

查看新的ROW_NUMBER函数。它是这样工作的:

SELECT ROW_NUMBER() OVER (ORDER BY EMPID ASC) AS ROWID, * FROM EMPLOYEE
于 2009-05-26T06:50:06.167 回答
6

Several of the answers above will work around the lack of a direct reference to a specific row, but will not work if changes occur to the other rows in a table. That is my criteria for which answers fall technically short.

A common use of Oracle's ROWID is to provide a (somewhat) stable method of selecting rows and later returning to the row to process it (e.g., to UPDATE it). The method of finding a row (complex joins, full-text searching, or browsing row-by-row and applying procedural tests against the data) may not be easily or safely re-used to qualify the UPDATE statement.

The SQL Server RID seems to provide the same functionality, but does not provide the same performance. That is the only issue I see, and unfortunately the purpose of retaining a ROWID is to avoid repeating an expensive operation to find the row in, say, a very large table. Nonetheless, performance for many cases is acceptable. If Microsoft adjusts the optimizer in a future release, the performance issue could be addressed.

It is also possible to simply use FOR UPDATE and keep the CURSOR open in a procedural program. However, this could prove expensive in large or complex batch processing.

Caveat: Even Oracle's ROWID would not be stable if the DBA, between the SELECT and the UPDATE, for example, were to rebuild the database, because it is the physical row identifier. So the ROWID device should only be used within a well-scoped task.

于 2011-09-28T16:54:13.690 回答
5

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

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

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

于 2013-09-18T20:28:07.303 回答
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
    
  • 使用临时表方法,将整个结果集连同IDENTITY() 函数生成的行 ID 一起存储到临时表中。创建临时表的成本很高,尤其是在处理大型表时。如果您的表中没有唯一键,请采用这种方法。

于 2009-05-26T06:22:43.913 回答
4

如果您只想要一个小数据集的基本行编号,那么这样的东西怎么样?

SELECT row_number() OVER (order by getdate()) as ROWID, * FROM Employees
于 2010-01-28T17:21:13.293 回答
1

请参阅http://msdn.microsoft.com/en-us/library/aa260631(v=SQL.80).aspx 在 SQL Server 中,时间戳与 DateTime 列不同。这用于唯一标识数据库中的一行,而不仅仅是一个表,而是整个数据库。这可用于乐观并发。例如 UPDATE [Job] SET [Name]=@Name, [XCustomData]=@XCustomData WHERE ([ModifiedTimeStamp]=@Original_ModifiedTimeStamp AND [GUID]=@Original_GUID

ModifiedTimeStamp 确保您正在更新原始数据,并且如果该行发生另一次更新,则会失败。

于 2013-03-12T02:33:00.530 回答
1

ROWID 是 Oracle 表上的隐藏列,因此,对于 SQL Server,构建您自己的列。添加一个名为 ROWID 的列,其默认值为NEWID()

如何做到这一点:将具有默认值的列添加到 SQL Server 中的现有表

于 2011-09-19T02:21:40.877 回答
0

我从 MS SQL 示例中获取了这个示例,您可以看到 @ID 可以与整数或 varchar 或其他任何东西互换。这是我一直在寻找的相同解决方案,所以我分享它。享受!!

-- UPDATE statement with CTE references that are correctly matched.
DECLARE @x TABLE (ID int, Stad int, Value int, ison bit);
INSERT @x VALUES (1, 0, 10, 0), (2, 1, 20, 0), (6, 0, 40, 0), (4, 1, 50, 0), (5, 3, 60, 0), (9, 6, 20, 0), (7, 5, 10, 0), (8, 8, 220, 0);
DECLARE @Error int;
DECLARE @id int;

WITH cte AS (SELECT top 1 * FROM @x WHERE Stad=6)
UPDATE x -- cte is referenced by the alias.
SET ison=1, @id=x.ID
FROM cte AS x

SELECT *, @id as 'random' from @x
GO
于 2011-09-23T18:46:39.513 回答
0

您可以使用以下方法获取 ROWID:

1.创建一个包含自动增量字段的新表

2.使用 Row_Number 分析函数根据您的要求获取序列。我更喜欢这个,因为它有助于您希望 row_id 以特定字段或字段组合的升序或降序方式

示例:Row_Number() Over(Partition by Deptno order by sal desc)

以上示例将根据每个部门的最高工资为您提供序列号。分区依据是可选的,您可以根据您的要求将其删除

于 2017-03-23T08:11:01.737 回答
-1

请试试

select NEWID()

来源:https ://docs.microsoft.com/en-us/sql/t-sql/data-types/uniqueidentifier-transact-sql

于 2017-07-24T14:37:39.260 回答