相当于Oracle';SQL Server中的RowID

相当于Oracle';SQL Server中的RowID,sql,sql-server,tsql,rowid,row-number,Sql,Sql Server,Tsql,Rowid,Row Number,在SQL Server中,Oracle的RowID的等效项是什么?来源: Oracle有一个rownum,可以使用rownum或row id访问表中的行。SQL Server中是否有与此等效的功能?或者如何生成 是否在SQL Server中以行号输出 SQL中没有与Oracle的rownum或row id直接等效的对象 服务器。严格地说,在关系数据库中 表没有排序,行id也没有实际意义。但是如果你 需要功能,考虑以下三种选择: 将标识列添加到表中 使用以下查询为每行生成行号。下面的查询为aut

在SQL Server中,Oracle的RowID的等效项是什么?

来源:

Oracle有一个rownum,可以使用rownum或row id访问表中的行。SQL Server中是否有与此等效的功能?或者如何生成 是否在SQL Server中以行号输出

SQL中没有与Oracle的rownum或row id直接等效的对象 服务器。严格地说,在关系数据库中 表没有排序,行id也没有实际意义。但是如果你 需要功能,考虑以下三种选择:

  • 标识
    列添加到表中

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

    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一起存储到临时表中。
    功能。创建临时表的成本很高,尤其是在 您正在处理大桌子。如果你不这样做,就采取这种方法 表中有一个唯一的键


如果希望在表中唯一标识行而不是结果集,则需要考虑使用类似于标识列的方法。请参阅SQL Server帮助中的“标识属性”。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
还有一篇关于行动态编号的文章。

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

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

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

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

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


如何做到这一点:

我从MS SQL示例中获取了这个示例,您可以看到@ID可以与integer或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

ROWID伪列

对于数据库中的每一行,ROWID伪列返回 行的地址。Oracle数据库rowid值包含以下信息 要定位行,必须执行以下操作:

  • 对象的数据对象编号
  • 行所在的数据文件中的数据块
  • 行在数据块中的位置(第一行为0)
  • 行所在的数据文件(第一个文件是1)。档案 数字是相对于表空间的
SQL Server中与此最接近的等价物是
rid
,它有三个组件
文件:Page:Slot

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

可以使用标量函数sys.fn\u PhysLocFormatter或sys.fn\u physlocrackerTVF将其转换为更可读的形式

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%%
,并返回匹配的行(如果有)

要反转前面提到的两个函数执行的过程,并获得与已知文件、页面、插槽值相对应的
二进制(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))

上面的几个答案可以解决缺少对特定行的直接引用的问题,但是如果表中的其他行发生更改,这些答案就不起作用了。这是我的标准,从技术上讲,答案是不够的

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

SQLServerRID似乎提供了相同的功能,但没有提供相同的性能。这是我看到的唯一问题,不幸的是,保留ROWID的目的是避免重复昂贵的操作,以便在(比如)非常大的表中查找该行。尽管如此,许多情况下的性能是可以接受的。如果Microsoft在将来的版本中调整优化器,那么性能问题可能会得到解决

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

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

请看 在SQL server中,时间戳与日期时间列不同。这用于唯一标识数据库中的一行,不仅仅是一个表,而是整个数据库。 这个可以
delete T from 
(select Row_Number() Over(Partition By BINARY_CHECKSUM(*) order by %%physloc%% ) As RowNumber, * From MyTable) T
Where T.RowNumber > 1