SQLServerでのOracleのRowIDに相当


84

SQL ServerのOracleのRowIDに相当するものは何ですか?


ステファニー:データに一意のキーがあると仮定します。これは、データが正規化されていると仮定しますが、これは誤った仮定である場合があります。したがって、SQLサーバーでのOracleのRowIDに相当するものは何ですか。
クリストファーマハン

回答:


117

Oracleドキュメントから

ROWID疑似列

データベース内の各行について、ROWID疑似列はその行のアドレスを返します。Oracle DatabaseのROWID値には、行を見つけるために必要な情報が含まれています。

  • オブジェクトのデータオブジェクト番号
  • 行が存在するデータファイル内のデータブロック
  • データブロック内の行の位置(最初の行は0)
  • 行が存在するデータファイル(最初のファイルは1)。ファイル番号は、表領域を基準にしています。

SQL Serverでこれに最も近いのは、rid3つのコンポーネントを持つですFile:Page:Slot

SQL Server 2008では、ドキュメント化されていない、サポートされていない%%physloc%%仮想列を使用して、これを確認できます。これbinary(8)により、最初の4バイトにページIDがあり、次にファイルIDに2バイト、続いてページ上のスロット位置に2バイトの値が返されます。

スカラー関数sys.fn_PhysLocFormatterまたはsys.fn_PhysLocCrackerTVFを使用して、これをより読みやすい形式に変換できます。

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)既知のFile、Page、Slot値に対応する値を取得するには、以下を使用できます。

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

SQL Server 2005の上では、文書化されていないと、サポートされていない仮想列%% LockResを使用することができます%%代わりに
ヘンリックHolmgaardホイヤーは、

絶対に正しい。%% LockResは%%「正しい方法」ではありません- SQLサーバの旧バージョンのデータにqucikや汚れの修正のために2008プリ場合にのみ使用
ヘンリックHolmgaardホイヤー

11

多くの列を持つ非常に大きなテーブルを重複排除する必要があり、速度が重要です。したがって、私はどのテーブルでも機能するこの方法を使用します。

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


9

結果セットではなくテーブル内の行を一意に識別したい場合は、IDENTITY列のようなものを使用することを検討する必要があります。SQLServerヘルプの「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の記事もあります。


ID列は、データベースではなくテーブルの行を一意に識別すると思います。
tuinstoel 2009年

これは本当ですが、OracleのドキュメントにあるROWIDの定義に適合しています。「外部データ型ROWIDはデータベーステーブルの特定の行を識別します」...しかし、私のタイプミスのためにこれを言っているようです。上。:)それを指摘してくれてありがとう。
Xiaofu

行「番号」はROWIDではありません。ROWIDには、一意の番号とは異なる行の物理的な場所が含まれています。特に、データベース内のすべてのテーブルで一意です(特別なストレージ手法が使用されている場合を除く)
a_horse_with_no_name 2011

6

上記の回答のいくつかは、特定の行への直接参照の欠如を回避しますが、テーブル内の他の行に変更が発生した場合は機能しません。それが私の答えが技術的に不足している基準です。

OracleのROWIDの一般的な使用法は、行を選択し、後で行に戻って処理する(たとえば、更新する)ための(ある程度)安定した方法を提供することです。行を検索する方法(複雑な結合、全文検索、または行ごとの参照とデータに対する手続き型テストの適用)は、UPDATEステートメントを修飾するために簡単または安全に再利用できない場合があります。

SQL Server RIDは同じ機能を提供しているように見えますが、同じパフォーマンスを提供していません。これが私が目にする唯一の問題です。残念ながら、ROWIDを保持する目的は、たとえば非常に大きなテーブルで行を見つけるためにコストのかかる操作を繰り返さないようにすることです。それにもかかわらず、多くの場合のパフォーマンスは許容範囲内です。Microsoftが将来のリリースでオプティマイザーを調整する場合、パフォーマンスの問題に対処できる可能性があります。

FOR UPDATEを使用して、手続き型プログラムでCURSORを開いたままにすることもできます。ただし、これは大規模または複雑なバッチ処理ではコストがかかる可能性があります。

警告:たとえば、SELECTとUPDATEの間のDBAがデータベースを再構築する場合、OracleのROWIDでさえ安定しません。これは、物理的な行識別子であるためです。したがって、ROWIDデバイスは、範囲の広いタスク内でのみ使用する必要があります。


3

小さなデータセットの基本的な行番号付けが必要な場合は、このようなものはどうでしょうか。

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

ただし、ROWIDが何であるかを知らずに、一部の視聴者が探しているクイック追加IDに対しては機能します。
Graeme 2012

3

http://vyaskn.tripod.com/programming_faq.htm#q17から:

Oracleには、行番号または行IDを使用してテーブルの行にアクセスするためのrownumがあります。SQL Serverにそれに相当するものはありますか?または、SQL Serverで行番号を使用して出力を生成する方法は?

SQLServerにはOracleのrownumまたはrowidに直接相当するものはありません。厳密に言えば、リレーショナルデータベースでは、テーブル内の行は順序付けられておらず、行IDは実際には意味がありません。ただし、その機能が必要な場合は、次の3つの選択肢を検討してください。

  • 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とともに一時テーブルに格納します。一時テーブルの作成は、特に大きなテーブルで作業している場合はコストがかかります。テーブルに一意のキーがない場合は、このアプローチを選択してください。


3

テーブルの行に永続的に番号を付ける場合は、SQLServerのRIDソリューションを使用しないでください。古い386でのAccessよりもパフォーマンスが低下します。SQLServerの場合は、IDENTITY列を作成し、その列をクラスター化された主キーとして使用します。これにより、永続的で高速な整数Bツリーがテーブルに配置され、さらに重要なことに、すべての非クラスター化インデックスがそれを使用して行を検索します。OracleのようにSQLServerで開発しようとすると、パフォーマンスの低いデータベースが作成されます。別のエンジンのふりをするのではなく、エンジンを最適化する必要があります。

また、NewID()を使用して主キーにGUIDを入力しないでください。挿入のパフォーマンスが低下します。GUIDを使用する必要がある場合は、列のデフォルトとしてNewSequentialID()を使用します。しかし、INTはそれでも高速です。

一方、クエリの結果の行に番号を付けるだけの場合は、クエリ列の1つとしてRowNumber Over()関数を使用します。




1

http://msdn.microsoft.com/en-us/library/aa260631(v=SQL.80).aspxを参照してください 。SQLサーバーでは、タイムスタンプはDateTime列と同じではありません。これは、テーブルだけでなくデータベース全体だけでなく、データベース内の行を一意に識別するために使用されます。これは、楽観的同時実行性に使用できます。たとえば、UPDATE [Job] SET [Name] = @ Name、[XCustomData] = @ XCustomData WHERE([ModifiedTimeStamp] = @ Original_ModifiedTimeStamp AND [GUID] = @ Original_GUID

ModifiedTimeStampは、元のデータを更新していることを確認し、行に別の更新が発生した場合は失敗します。


0

この例はMSSQLの例から取ったもので、@ 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

0

以下に示す方法を使用して、ROWIDを取得できます。

1.自動インクリメントフィールドを含む新しいテーブルを作成します

2. Row_Number分析関数を使用して、要件に基づいてシーケンスを取得します。特定のフィールドまたはフィールドの組み合わせの昇順または降順でrow_idが必要な状況で役立つため、これをお勧めします。

サンプル:Row_Number()Over(Deptnoによるパーティションsal descによる順序)

上記のサンプルは、各部門の最高給与に基づいたシーケンス番号を示しています。パーティションバイはオプションであり、要件に応じて削除できます。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.