Tương đương với RowID của Oracle trong SQL Server


82

RowID của Oracle trong SQL Server có gì tương đương?


Stephanie: giả định là có một khóa duy nhất trong dữ liệu, giả định rằng dữ liệu được chuẩn hóa, đôi khi đây là một giả định không chính xác. Do đó, tương đương với RowID của Oracle trong máy chủ SQL.
Christopher Mahan

Câu trả lời:


115

Từ tài liệu Oracle

Cột giả ROWID

Đối với mỗi hàng trong cơ sở dữ liệu, cột giả ROWID trả về địa chỉ của hàng. Các giá trị rowid của Cơ sở dữ liệu Oracle chứa thông tin cần thiết để định vị một hàng:

  • Số đối tượng dữ liệu của đối tượng
  • Khối dữ liệu trong tệp dữ liệu chứa hàng
  • Vị trí của hàng trong khối dữ liệu (hàng đầu tiên là 0)
  • Tệp dữ liệu chứa hàng (tệp đầu tiên là 1). Số tệp có liên quan đến không gian bảng.

Tương đương gần nhất với điều này trong SQL Server là ridcó ba thành phần File:Page:Slot.

Trong SQL Server 2008, có thể sử dụng %%physloc%%cột ảo không có tài liệu và không được hỗ trợ để xem điều này. Điều này trả về một binary(8)giá trị với ID trang trong bốn byte đầu tiên, sau đó là 2 byte cho ID tệp, tiếp theo là 2 byte cho vị trí vị trí trên trang.

Hàm vô hướng sys.fn_PhysLocFormatterhoặc sys.fn_PhysLocCrackerTVF có thể được sử dụng để chuyển đổi nó thành một dạng dễ đọc hơn

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

Đầu ra mẫu

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

Lưu ý rằng điều này không được bộ xử lý truy vấn tận dụng. Trong khi có thể sử dụng điều này trong một WHEREmệnh đề

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

SQL Server sẽ không trực tiếp tìm kiếm hàng được chỉ định. Thay vào đó, nó sẽ quét toàn bộ bảng, đánh giá %%physloc%%từng hàng và trả về hàng phù hợp (nếu có).

Để đảo ngược quá trình được thực hiện bởi 2 hàm đã đề cập trước đó và nhận binary(8)giá trị tương ứng với các giá trị Tệp, Trang, Khe đã biết, bạn có thể sử dụng giá trị bên dưới.

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))

Trên SQL Server 2005, bạn có thể sử dụng các cột ảo không có tài liệu và không được hỗ trợ %% LockRes %% thay thế
Henrik Holmgaard Høyer

chính xác tuyệt đối. %% LockRes %% không phải là "cách chính xác" - chỉ sử dụng nếu cho các bản sửa lỗi qucik và dơ bẩn đối với dữ liệu trên các phiên bản cũ của máy chủ sql trước năm 2008
Henrik Holmgaard Høyer

11

Tôi phải suy luận một bảng rất lớn với nhiều cột và tốc độ là quan trọng. Vì vậy, tôi sử dụng phương pháp này hoạt động cho bất kỳ bảng nào:

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

9

Kiểm tra chức năng ROW_NUMBER mới . Nó hoạt động như thế này:

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

14
Tôi nghĩ rằng đây là một sự thay thế cho rownum chứ không phải rowid.
tuinstoel

9

Nếu bạn muốn xác định duy nhất một hàng trong bảng chứ không phải tập kết quả của mình, thì bạn cần xem xét bằng cách sử dụng cột nào đó như cột IDENTITY. Xem "thuộc tính IDENTITY" trong phần trợ giúp của SQL Server. SQL Server không tự động tạo ID cho mỗi hàng trong bảng như Oracle làm, vì vậy bạn phải gặp khó khăn khi tạo cột ID của riêng mình và tìm nạp rõ ràng nó trong truy vấn của bạn.

CHỈNH SỬA: để đánh số động các hàng tập kết quả, hãy xem bên dưới, nhưng điều đó có thể sẽ tương đương với ROWNUM của Oracle và tôi giả sử từ tất cả các nhận xét trên trang mà bạn muốn những thứ ở trên. Đối với SQL Server 2005 trở lên, bạn có thể sử dụng chức năng Chức năng Xếp hạng mới để đánh số động các hàng.

Ví dụ: tôi làm điều này trên một truy vấn của tôi:

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

Sẽ cung cấp cho bạn:

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

Cũng có một bài viết trên support.microsoft.com về cách đánh số hàng động.


Tôi nghĩ rằng một cột nhận dạng xác định duy nhất một hàng trong bảng nhưng không xác định trong cơ sở dữ liệu.
tuinstoel

Điều này đúng, nhưng điều đó phù hợp với định nghĩa về ROWID mà tôi thấy trong tài liệu Oracle: "Loại dữ liệu bên ngoài ROWID xác định một hàng cụ thể trong bảng cơ sở dữ liệu" ... nhưng tôi thấy bạn đang nói điều này vì lỗi đánh máy của tôi ở hàng đầu. :) Cảm ơn vì đã chỉ ra điều đó.
Xiaofu

Một "số" không phải là ROWID. ROWID chứa vị trí thực của hàng mà nó khác với một số duy nhất. Đặc biệt nó là duy nhất accross tất cả các bảng trong cơ sở dữ liệu (với một số trường hợp ngoại lệ khi các kỹ thuật bảo quản đặc biệt được sử dụng)
a_horse_with_no_name

6

Một số các câu trả lời ở trên sẽ làm việc xung quanh việc thiếu một tham chiếu trực tiếp đến một hàng cụ thể, nhưng sẽ không làm việc nếu thay đổi xảy ra đối với các hàng khác trong một bảng. Đó là tiêu chí của tôi cho những câu trả lời ngắn gọn về mặt kỹ thuật.

Cách sử dụng phổ biến của ROWID của Oracle là cung cấp một phương pháp (phần nào) ổn định để chọn hàng và sau đó quay trở lại hàng để xử lý nó (ví dụ: CẬP NHẬT nó). Phương pháp tìm một hàng (các phép nối phức tạp, tìm kiếm toàn văn bản hoặc duyệt từng hàng một và áp dụng các kiểm tra thủ tục đối với dữ liệu) có thể không được sử dụng lại một cách dễ dàng hoặc an toàn để đủ điều kiện cho câu lệnh UPDATE.

SQL Server RID dường như cung cấp cùng một chức năng, nhưng không cung cấp cùng một hiệu suất. Đó là vấn đề duy nhất mà tôi thấy, và thật không may, mục đích của việc giữ lại ROWID là để tránh lặp lại một thao tác tốn kém để tìm hàng trong một bảng rất lớn. Tuy nhiên, hiệu suất trong nhiều trường hợp có thể chấp nhận được. Nếu Microsoft điều chỉnh trình tối ưu hóa trong bản phát hành trong tương lai, vấn đề hiệu suất có thể được giải quyết.

Cũng có thể chỉ cần sử dụng FOR UPDATE và giữ CURSOR mở trong một chương trình thủ tục. Tuy nhiên, điều này có thể gây tốn kém trong quá trình xử lý hàng loạt lớn hoặc phức tạp.

Lưu ý: Ngay cả ROWID của Oracle cũng sẽ không ổn định nếu ví dụ như DBA, giữa SELECT và UPDATE, xây dựng lại cơ sở dữ liệu, vì nó là định danh hàng vật lý. Vì vậy, thiết bị ROWID chỉ nên được sử dụng trong một nhiệm vụ có phạm vi tốt.


3

nếu bạn chỉ muốn đánh số hàng cơ bản cho một tập dữ liệu nhỏ, vậy còn cách đánh số như thế này thì sao?

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

8
Không phải là những gì một người ồn ào.
Trang Stephanie

Nhưng nó hoạt động cho id được thêm nhanh chóng mà một số người xem sẽ tìm kiếm, không biết ROWID là gì.
Graeme

3

Từ http://vyaskn.tripod.com/programming_faq.htm#q17 :

Oracle có một rownum để truy cập các hàng của bảng bằng cách sử dụng số hàng hoặc id hàng. Có bất kỳ tương đương nào cho điều đó trong SQL Server không? Hoặc làm thế nào để tạo đầu ra với số hàng trong SQL Server?

Không có tương đương trực tiếp với id hàng hoặc rownum của Oracle trong SQL Server. Nói một cách chính xác, trong cơ sở dữ liệu quan hệ, các hàng trong bảng không được sắp xếp theo thứ tự và id hàng sẽ không thực sự có ý nghĩa. Nhưng nếu bạn cần chức năng đó, hãy xem xét ba lựa chọn thay thế sau:

  • Thêm một IDENTITYcột vào bảng của bạn.

  • Sử dụng truy vấn sau để tạo số hàng cho mỗi hàng. Truy vấn sau tạo một số hàng cho mỗi hàng trong bảng tác giả của cơ sở dữ liệu quán rượu. Để truy vấn này hoạt động, bảng phải có một khóa duy nhất.

    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
    
  • Sử dụng cách tiếp cận bảng tạm thời, để lưu trữ toàn bộ tập kết quả vào một bảng tạm thời, cùng với một id hàng được tạo bởi IDENTITY() hàm. Tạo một bảng tạm thời sẽ rất tốn kém, đặc biệt là khi bạn đang làm việc với các bảng lớn. Hãy thực hiện cách tiếp cận này, nếu bạn không có khóa duy nhất trong bảng của mình.


3

Nếu bạn muốn đánh số vĩnh viễn các hàng trong bảng, Vui lòng không sử dụng giải pháp RID cho SQL Server. Nó sẽ hoạt động kém hơn Access trên 386. Đối với SQL Server, chỉ cần tạo một cột IDENTITY và sử dụng cột đó làm khóa chính nhóm. Điều này sẽ đặt một Cây số nguyên nhanh, vĩnh viễn trên bảng và quan trọng hơn là mọi chỉ mục không phân cụm sẽ sử dụng nó để định vị các hàng. Nếu bạn cố gắng phát triển trong SQL Server như thể đó là Oracle, bạn sẽ tạo ra một cơ sở dữ liệu hoạt động kém. Bạn cần phải tối ưu hóa cho động cơ, không phải giả vờ đó là một động cơ khác.

Ngoài ra, vui lòng không sử dụng NewID () để điền vào Khóa chính với các GUID, bạn sẽ giết hiệu suất chèn. Nếu bạn phải sử dụng GUID, hãy sử dụng NewSequentialID () làm cột mặc định. Nhưng INT vẫn sẽ nhanh hơn.

Mặt khác, nếu bạn chỉ muốn đánh số các hàng là kết quả của một truy vấn, hãy sử dụng hàm RowNumber Over () làm một trong các cột truy vấn.




1

Vui lòng xem http://msdn.microsoft.com/en-us/library/aa260631(v=SQL.80).aspx Trong máy chủ SQL, dấu thời gian không giống với cột DateTime. Điều này được sử dụng để xác định duy nhất một hàng trong cơ sở dữ liệu, không chỉ một bảng mà toàn bộ cơ sở dữ liệu. Điều này có thể được sử dụng cho đồng thời lạc quan. ví dụ: UPDATE [Job] SET [Name] = @ Name, [XCustomData] = @ XCustomData WHERE ([ModifiedTimeStamp] = @ Original_ModifiedTimeStamp VÀ [GUID] = @ Original_GUID

Mod ModifiedTimeStamp đảm bảo rằng bạn đang cập nhật dữ liệu gốc và sẽ không thành công nếu một bản cập nhật khác đã xảy ra với hàng.


0

Tôi lấy ví dụ này từ ví dụ MS SQL và bạn có thể thấy @ID có thể được thay thế bằng số nguyên hoặc varchar hoặc bất cứ thứ gì. Đây cũng là giải pháp mà tôi đang tìm kiếm, vì vậy tôi đang chia sẻ nó. Thưởng thức!!

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

0

Bạn có thể lấy ROWID bằng cách sử dụng các phương pháp được cung cấp bên dưới:

1.Tạo một bảng mới với trường tăng tự động trong đó

2.Sử dụng hàm phân tích Row_Number để lấy chuỗi dựa trên yêu cầu của bạn. Tôi thích điều này hơn vì nó hữu ích trong những trường hợp bạn muốn row_id theo cách tăng dần hoặc giảm dần của một trường cụ thể hoặc kết hợp các trường

Mẫu: Row_Number () Over (Partition by Deptno order by sal desc)

Mẫu trên sẽ cung cấp cho bạn số thứ tự dựa trên mức lương cao nhất của từng bộ phận. Phân vùng theo tùy chọn và bạn có thể xóa tùy theo yêu cầu của mình

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.