SQL Server中Oracle的RowID的等价物
在SQL Server中,Oracle的RowID是什么?
从Oracle文档
ROWID伪列
对于数据库中的每一行,ROWID伪列都返回该行的地址。 Oracle数据库rowid值包含查找行所需的信息:
- 对象的数据对象编号
- 行所在数据文件中的数据块
- 数据块中行的位置(第一行是0)
- 行所在的数据文件(第一个文件是1)。 文件编号是相对于表空间。
在SQL Server中最接近于此的是具有三个组件File:Page:Slot
。
在SQL Server 2008中,可以使用未logging的和不受支持的%%physloc%%
虚拟列来查看。 这会返回一个binary(8)
值,其中前四个字节中包含页面标识,然后是2个字节的文件标识,后面是2个字节的页面上的插槽位置。
可以使用标量函数sys.fn_PhysLocFormatter
或sys.fn_PhysLocCracker
TVF将其转换为更易读的forms
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 不会直接寻find指定的行。 相反,它会执行全表扫描,为每行评估%%physloc%%
并返回匹配的(如果有的话)。
为了逆转前面提到的两个函数所执行的过程并获得与已知的文件,页面,时隙值相对应的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))
如果要唯一标识表中的行而不是结果集,则需要使用类似于IDENTITY列的东西。 请参阅SQL Server帮助中的“IDENTITY属性”。 SQL Server不像Oracle那样自动为表中的每一行生成一个ID,所以你不得不去创build自己的ID列,并在查询中明确地获取它。
编辑:结果集行的dynamic编号见下文,但这可能是一个相当于Oracle的ROWNUM,我假设从上面的东西在页面上的所有意见。 对于SQL Server 2005及更高版本,您可以使用新的sorting函数function来实现行的dynamic编号。
例如,我在查询我的时候这样做:
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上还有一篇关于dynamic编号行的文章。
查看新的ROW_NUMBER函数。 它是这样工作的:
SELECT ROW_NUMBER() OVER (ORDER BY EMPID ASC) AS ROWID, * FROM EMPLOYEE
上面的几个答案将围绕缺less对特定行的直接引用而起作用 ,但如果表中的其他行发生更改, 则不起作用 。 这是我的答案在技术上缩短的标准。
Oracle ROWID的一个常见用途是提供一个(某种程度上)稳定的select行的方法,然后返回到行来处理它(例如更新它)。 查找行(复杂连接,全文search,或逐行浏览和对数据应用程序testing)的方法可能不容易或安全地重新用于限定UPDATE语句。
SQL Server RID似乎提供了相同的function,但不提供相同的性能。 这是我所看到的唯一的问题,不幸的是,保留ROWID的目的是为了避免重复昂贵的操作,例如在一个非常大的表格中查找行。 尽pipe如此,许多情况下的performance是可以接受的。 如果Microsoft在未来版本中调整优化器,则可以解决性能问题。
也可以简单地使用FOR UPDATE并在程序程序中保持CURSOR打开。 但是,这在大型或复杂的批处理中可能会很昂贵。
警告:如果Oracle和UPDATE之间的DBA重build数据库,即使Oracle的ROWID也不稳定,因为它是物理行标识符。 所以ROWID设备只能在一个合适的范围内使用。
从http://vyaskn.tripod.com/programming_faq.htm#q17 :
Oracle有一个rownum来使用行号或行号访问表的行。 在SQL Server中是否有任何等价物? 或者如何在SQL Server中用行号生成输出?
在SQL Server中,没有直接等价于Oracle的rownum或row id。 严格地说,在一个关系数据库中,表中的行不是有序的,行ID是没有意义的。 但是如果你需要这个function,请考虑以下三种select:
将一个
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。 创build一个临时表会代价高昂,特别是在处理大型表时。 如果您的表中没有唯一的密钥,请使用此方法。
如果要永久性地为表中的行编号,请不要使用SQL Server的RID解决scheme。 它将比旧的386上的Access性能更差。对于SQL Server,只需创build一个IDENTITY列,并将该列用作群集主键。 这将在表格上放置一个永久的,快速的Integer B-Tree,更重要的是每个非聚集索引都将使用它来定位行。 如果您尝试在SQL Server中开发,就好像它是Oracle,那么您将创build一个性能不佳的数据库。 你需要为引擎进行优化,而不是假装它是一个不同的引擎。
另外,请不要使用NewID()来填充带有GUID的主键,否则会导致插入性能下降。 如果您必须使用GUID使用NewSequentialID()作为列默认值。 但是INT仍然会更快。
另一方面,如果您只想对查询生成的行进行编号,请使用RowNumber Over()函数作为查询列之一。
如果你只是想要一个小的数据集的基本行编号,那么这样的东西呢?
SELECT row_number() OVER (order by getdate()) as ROWID, * FROM Employees
我必须用很多列重复一个非常大的桌子,速度很重要。 因此,我使用这种方法适用于任何表格:
delete T from (select Row_Number() Over(Partition By BINARY_CHECKSUM(*) order by %%physloc%% ) As RowNumber, * From MyTable) T Where T.RowNumber > 1
ROWID是Oracle表上隐藏的一列,所以对于SQL Server来说,build立你自己的。 添加一个名为ROWID的列,其默认值为NEWID()
。
如何做到这一点: 添加具有默认值的列到SQL Server中的现有表
请参阅http://msdn.microsoft.com/zh-cn/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确保您正在更新原始数据,并且如果该行发生另一个更新,将会失败。
我从MS SQL例子中拿出了这个例子,你可以看到@ID可以和integer或者varchar或者其他什么东西交换。 这是我一直在寻找的解决scheme,所以我分享了。 请享用!!
-- 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:
1.创build一个新的带有自动增量栏的表格
2.使用Row_Number分析函数根据您的要求获取序列。我更喜欢这样做,因为它有助于在您希望row_id以特定字段或字段组合的升序或降序方式
示例:Row_Number()Over(按des命令分区,按sal desc)
上面的样本会给你根据每个部门的最高工资序号。分区是可选的,你可以根据你的要求删除它
请尝试
select NEWID()
源: https : //docs.microsoft.com/en-us/sql/t-sql/data-types/uniqueidentifier-transact-sql