相当于 SQL Server 中 Oracle 的 RowID

发布于 2024-07-21 11:27:32 字数 41 浏览 5 评论 0原文

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

What's the equivalent of Oracle's RowID in SQL Server?

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

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

发布评论

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

评论(13

鹿童谣 2024-07-28 11:27:32

来自 Oracle 文档

ROWID 伪列

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

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

SQL Server 中与此最接近的等效项是 rid,它具有三个组件 File:Page:Slot

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

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

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子句中使用它,但

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

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

要反转前面提到的 2 个函数执行的过程并获取与已知 File、Page、Slot 值相对应的 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))

From the Oracle docs

ROWID Pseudocolumn

For each row in the database, the ROWID pseudocolumn returns the
address of the row. Oracle Database rowid values contain information
necessary to locate a row:

  • The data object number of the object
  • The data block in the datafile in which the row resides
  • The position of the row in the data block (first row is 0)
  • The datafile in which the row resides (first file is 1). The file
    number is relative to the tablespace.

The closest equivalent to this in SQL Server is the rid which has three components File:Page:Slot.

In SQL Server 2008 it is possible to use the undocumented and unsupported %%physloc%% virtual column to see this. This returns a binary(8) value with the Page ID in the first four bytes, then 2 bytes for File ID, followed by 2 bytes for the slot location on the page.

The scalar function sys.fn_PhysLocFormatter or the sys.fn_PhysLocCracker TVF can be used to convert this into a more readable form

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

Example Output

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

Note that this is not leveraged by the query processor. Whilst it is possible to use this in a WHERE clause

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

SQL Server will not directly seek to the specified row. Instead it will do a full table scan, evaluate %%physloc%% for each row and return the one that matches (if any do).

To reverse the process carried out by the 2 previously mentioned functions and get the binary(8) value corresponding to known File,Page,Slot values the below can be used.

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))
〆凄凉。 2024-07-28 11:27:32

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

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

I have to dedupe a very big table with many columns and speed is important. Thus I use this method which works for any table:

delete T from 
(select Row_Number() Over(Partition By BINARY_CHECKSUM(*) order by %%physloc%% ) As RowNumber, * From MyTable) T
Where T.RowNumber > 1
沒落の蓅哖 2024-07-28 11:27:32

如果您想唯一标识表中的一行而不是结果集,那么您需要考虑使用 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

会给您:

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 关于动态编号行。

If you want to uniquely identify a row within the table rather than your result set, then you need to look at using something like an IDENTITY column. See "IDENTITY property" in the SQL Server help. SQL Server does not auto-generate an ID for each row in the table as Oracle does, so you have to go to the trouble of creating your own ID column and explicitly fetch it in your query.

EDIT: for dynamic numbering of result set rows see below, but that would probably an equivalent for Oracle's ROWNUM and I assume from all the comments on the page that you want the stuff above.
For SQL Server 2005 and later you can use the new Ranking Functions function to achieve dynamic numbering of rows.

For example I do this on a query of mine:

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

Will give you:

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

There's also an article on support.microsoft.com on dynamically numbering rows.

何其悲哀 2024-07-28 11:27:32

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

SELECT ROW_NUMBER() OVER (ORDER BY EMPID ASC) AS ROWID, * FROM EMPLOYEE

Check out the new ROW_NUMBER function. It works like this:

SELECT ROW_NUMBER() OVER (ORDER BY EMPID ASC) AS ROWID, * FROM EMPLOYEE
殤城〤 2024-07-28 11:27:32

上面的几个答案将解决缺乏对特定行的直接引用的问题,但是如果表中的其他行发生更改,将不起作用。 这就是我对答案在技术上不足的标准。

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

SQL Server RID 似乎提供相同的功能,但不提供相同的性能。 这是我看到的唯一问题,不幸的是,保留 ROWID 的目的是避免重复昂贵的操作来查找行(例如,在一个非常大的表中)。 尽管如此,许多情况下的性能是可以接受的。 如果微软在未来的版本中调整优化器,性能问题可能会得到解决。

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

警告:如果 DBA 在 SELECT 和 UPDATE 之间重建数据库,即使 Oracle 的 ROWID 也不稳定,因为它是物理行标识符。 因此,ROWID 设备只能在范围明确的任务中使用。

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.

油焖大侠 2024-07-28 11:27:32

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

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

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

If you want to permanently number the rows in the table, Please don't use the RID solution for SQL Server. It will perform worse than Access on an old 386. For SQL Server simply create an IDENTITY column, and use that column as a clustered primary key. This will place a permanent, fast Integer B-Tree on the table, and more importantly every non-clustered index will use it to locate rows. If you try to develop in SQL Server as if it's Oracle you'll create a poorly performing database. You need to optimize for the engine, not pretend it's a different engine.

also, please don't use the NewID() to populate the Primary Key with GUIDs, you'll kill insert performance. If you must use GUIDs use NewSequentialID() as the column default. But INT will still be faster.

If on the other hand, you simply want to number the rows that result from a query, use the RowNumber Over() function as one of the query columns.

甜尕妞 2024-07-28 11:27:32

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

SELECT row_number() OVER (order by getdate()) as ROWID, * FROM Employees

if you just want basic row numbering for a small dataset, how about someting like this?

SELECT row_number() OVER (order by getdate()) as ROWID, * FROM Employees
笔芯 2024-07-28 11:27:32

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

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

没有直接相当于 SQL 中 Oracle 的 rownum 或 row id
服务器。 严格来说,在关系数据库中,
表没有排序,行 ID 没有任何意义。 但如果你
需要该功能,请考虑以下三种替代方案:

  • IDENTITY 列添加到您的表格中。

  • 使用以下查询为每行生成行号。 以下查询为authors中的每一行生成一个行号
    酒吧数据库表。 为了使该查询工作,该表必须有一个
    唯一的密钥。

    选择(选择计数(i.au_id)  
              来自酒吧..作者我  
              WHERE i.au_id >= o.au_id ) AS RowID,  
             au_fname + ' ' + au_lname AS '作者姓名' 
      来自酒吧..作者 o 
      按行 ID 排序 
      
  • 使用临时表方法,将整个结果集以及由 IDENTITY() 生成的行 ID 存储到临时表中
    功能。 创建临时表的成本很高,尤其是在
    您正在使用大桌子。 如果你不这样做,请采用这种方法
    您的表中有一个唯一的键。

From http://vyaskn.tripod.com/programming_faq.htm#q17:

Oracle has a rownum to access rows of a table using row number or row id. Is there any equivalent for that in SQL Server? Or how to generate
output with row number in SQL Server?

There is no direct equivalent to Oracle's rownum or row id in SQL
Server. Strictly speaking, in a relational database, rows within a
table are not ordered and a row id won't really make sense. But if you
need that functionality, consider the following three alternatives:

  • Add an IDENTITY column to your table.

  • Use the following query to generate a row number for each row. The following query generates a row number for each row in the authors
    table of pubs database. For this query to work, the table must have a
    unique key.

    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
    
  • Use a temporary table approach, to store the entire resultset into a temporary table, along with a row id generated by the IDENTITY()
    function. Creating a temporary table will be costly, especially when
    you are working with large tables. Go for this approach, if you don't
    have a unique key in your table.

岛徒 2024-07-28 11:27:32

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

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

ROWID is a hidden column on Oracle tables, so, for SQL Server, build your own. Add a column called ROWID with a default value of NEWID().

How to do that: Add column, with default value, to existing table in SQL Server

一枫情书 2024-07-28 11:27:32

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

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

Please see http://msdn.microsoft.com/en-us/library/aa260631(v=SQL.80).aspx
In SQL server a timestamp is not the same as a DateTime column. This is used to uniquely identify a row in a database, not just a table but the entire database.
This can be used for optimistic concurrency. for example
UPDATE [Job] SET [Name]=@Name, [XCustomData]=@XCustomData WHERE ([ModifiedTimeStamp]=@Original_ModifiedTimeStamp AND [GUID]=@Original_GUID

the ModifiedTimeStamp ensures that you are updating the original data and will fail if another update has occurred to the row.

明媚如初 2024-07-28 11:27:32

我从 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

I took this example from MS SQL example and you can see the @ID can be interchanged with integer or varchar or whatever. This was the same solution I was looking for, so I am sharing it. Enjoy!!

-- 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
画尸师 2024-07-28 11:27:32

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

1.创建一个新表,其中包含自动递增字段

2.使用 Row_Number 分析函数根据您的要求获取序列。我更喜欢这个,因为它在您需要的情况下有所帮助您想要特定字段或字段组合的 row_id 按升序还是降序排列

Sample:Row_Number() Over(Partition by Deptno order by sal desc)

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

You can get the ROWID by using the methods given below :

1.Create a new table with auto increment field in it

2.Use Row_Number analytical function to get the sequence based on your requirement.I would prefer this because it helps in situations where you are you want the row_id on ascending or descending manner of a specific field or combination of fields

Sample:Row_Number() Over(Partition by Deptno order by sal desc)

Above sample will give you the sequence number based on highest salary of each department.Partition by is optional and you can remove it according to your requirements

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