SQL ServerのOracleのRowIDに相当するものは何ですか?
回答:
ROWID疑似列
データベース内の各行について、ROWID疑似列はその行のアドレスを返します。Oracle DatabaseのROWID値には、行を見つけるために必要な情報が含まれています。
- オブジェクトのデータオブジェクト番号
- 行が存在するデータファイル内のデータブロック
- データブロック内の行の位置(最初の行は0)
- 行が存在するデータファイル(最初のファイルは1)。ファイル番号は、表領域を基準にしています。
SQL Serverでこれに最も近いのは、rid
3つのコンポーネントを持つですFile:Page:Slot
。
SQL Server 2008では、ドキュメント化されていない、サポートされていない%%physloc%%
仮想列を使用して、これを確認できます。これbinary(8)
により、最初の4バイトにページIDがあり、次にファイルIDに2バイト、続いてページ上のスロット位置に2バイトの値が返されます。
スカラー関数sys.fn_PhysLocFormatter
またはsys.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)
既知の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))
新しいROW_NUMBER関数を確認してください。それはこのように動作します:
SELECT ROW_NUMBER() OVER (ORDER BY EMPID ASC) AS ROWID, * FROM EMPLOYEE
結果セットではなくテーブル内の行を一意に識別したい場合は、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の記事もあります。
上記の回答のいくつかは、特定の行への直接参照の欠如を回避しますが、テーブル内の他の行に変更が発生した場合は機能しません。それが私の答えが技術的に不足している基準です。
OracleのROWIDの一般的な使用法は、行を選択し、後で行に戻って処理する(たとえば、更新する)ための(ある程度)安定した方法を提供することです。行を検索する方法(複雑な結合、全文検索、または行ごとの参照とデータに対する手続き型テストの適用)は、UPDATEステートメントを修飾するために簡単または安全に再利用できない場合があります。
SQL Server RIDは同じ機能を提供しているように見えますが、同じパフォーマンスを提供していません。これが私が目にする唯一の問題です。残念ながら、ROWIDを保持する目的は、たとえば非常に大きなテーブルで行を見つけるためにコストのかかる操作を繰り返さないようにすることです。それにもかかわらず、多くの場合のパフォーマンスは許容範囲内です。Microsoftが将来のリリースでオプティマイザーを調整する場合、パフォーマンスの問題に対処できる可能性があります。
FOR UPDATEを使用して、手続き型プログラムでCURSORを開いたままにすることもできます。ただし、これは大規模または複雑なバッチ処理ではコストがかかる可能性があります。
警告:たとえば、SELECTとUPDATEの間のDBAがデータベースを再構築する場合、OracleのROWIDでさえ安定しません。これは、物理的な行識別子であるためです。したがって、ROWIDデバイスは、範囲の広いタスク内でのみ使用する必要があります。
小さなデータセットの基本的な行番号付けが必要な場合は、このようなものはどうでしょうか。
SELECT row_number() OVER (order by getdate()) as ROWID, * FROM Employees
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とともに一時テーブルに格納します。一時テーブルの作成は、特に大きなテーブルで作業している場合はコストがかかります。テーブルに一意のキーがない場合は、このアプローチを選択してください。
テーブルの行に永続的に番号を付ける場合は、SQLServerのRIDソリューションを使用しないでください。古い386でのAccessよりもパフォーマンスが低下します。SQLServerの場合は、IDENTITY列を作成し、その列をクラスター化された主キーとして使用します。これにより、永続的で高速な整数Bツリーがテーブルに配置され、さらに重要なことに、すべての非クラスター化インデックスがそれを使用して行を検索します。OracleのようにSQLServerで開発しようとすると、パフォーマンスの低いデータベースが作成されます。別のエンジンのふりをするのではなく、エンジンを最適化する必要があります。
また、NewID()を使用して主キーにGUIDを入力しないでください。挿入のパフォーマンスが低下します。GUIDを使用する必要がある場合は、列のデフォルトとしてNewSequentialID()を使用します。しかし、INTはそれでも高速です。
一方、クエリの結果の行に番号を付けるだけの場合は、クエリ列の1つとしてRowNumber Over()関数を使用します。
してみてください
select NEWID()
ソース:https://docs.microsoft.com/en-us/sql/t-sql/data-types/uniqueidentifier-transact-sql
ROWIDはOracleテーブルの非表示列であるため、SQLServerの場合は独自の列を作成します。デフォルト値がNEWID()
。のROWIDという列を追加します。
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は、元のデータを更新していることを確認し、行に別の更新が発生した場合は失敗します。
この例は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
以下に示す方法を使用して、ROWIDを取得できます。
1.自動インクリメントフィールドを含む新しいテーブルを作成します
2. Row_Number分析関数を使用して、要件に基づいてシーケンスを取得します。特定のフィールドまたはフィールドの組み合わせの昇順または降順でrow_idが必要な状況で役立つため、これをお勧めします。
サンプル:Row_Number()Over(Deptnoによるパーティションsal descによる順序)
上記のサンプルは、各部門の最高給与に基づいたシーケンス番号を示しています。パーティションバイはオプションであり、要件に応じて削除できます。