SQL Server中Oracle的RowID的等价物

时间:2009-05-26 06:20:05

标签: sql sql-server tsql rowid row-number

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

13 个答案:

答案 0 :(得分:114)

From the Oracle docs

  

ROWID Pseudocolumn

     

对于数据库中的每一行,ROWID伪列返回   行的地址。 Oracle数据库rowid值包含信息   找到一行是必要的:

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

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

在SQL Server 2008中,可以使用未记录且不受支持的%%physloc%%虚拟列来查看此内容。这将返回一个binary(8)值,其中Page ID在前四个字节中,然后是2个字节用于文件ID,后面是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个函数执行的过程,并获得与已知文件,页面,插槽值对应的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))

答案 1 :(得分: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的文章。

答案 2 :(得分:8)

查看新的ROW_NUMBER功能。它的工作原理如下:

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

答案 3 :(得分:6)

上面的几个答案将解决缺少对特定行的直接引用,但如果表中的其他行发生更改,将无效 。这是我的答案在技术上很短的标准。

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

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

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

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

答案 4 :(得分:6)

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

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

答案 5 :(得分:3)

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

  

Oracle有一个rownum来使用行号或行ID访问表的行。在SQL Server中有没有相同的东西?或者如何生成   在SQL Server中使用行号输出?

     

在SQL中没有直接等同于Oracle的rownum或row id   服务器。严格地说,在关系数据库中,行内的行   table没有排序,行id也没有意义。但如果你   需要该功能,请考虑以下三种选择:

     
      
  • 在表格中添加IDENTITY列。

  •   
  • 使用以下查询为每行生成行号。以下查询为作者中的每一行生成行号   酒吧数据库表。要使此查询起作用,表必须具有   独特的关键。

    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   功能。创建临时表的成本很高,尤其是在使用时   你正在使用大表。如果不这样做,请采用这种方法   在你的桌子上有一个独特的钥匙。

  •   

答案 6 :(得分:3)

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

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

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

答案 7 :(得分:2)

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

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

答案 8 :(得分:2)

答案 9 :(得分:1)

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

如何做到:Add column, with default value, to existing table in SQL Server

答案 10 :(得分:1)

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

ModifiedTimeStamp可确保您更新原始数据,如果该行发生了其他更新,则会失败。

答案 11 :(得分: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

答案 12 :(得分:0)

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

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

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

示例:Row_Number()Over(由sal desc按Deptno顺序分区)

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