web-dev-qa-db-ja.com

IDENTITY列のみを持つテーブルに複数の行を挿入する

dbo.Groupsというテーブルが次のように定義されています。

CREATE TABLE dbo.Groups
(
  GroupID int NOT NULL IDENTITY (1,1) PRIMARY KEY
);

テーブルは実際には1つのIDENTITY列だけで構成されています。

時には、一度に複数の行を挿入して、生成されたIDを取得したい場合があります。 (ID句で使用するOUTPUT列が1つある@outputという定義済みのテーブル変数がすでにあります。)

singleの行の場合、どのようにすればよいかがわかります。

INSERT INTO
  dbo.GroupID
OUTPUT
  inserted.GroupID INTO @output (ID)
DEFAULT VALUES
;

ただし、一度に2つ以上挿入できるようにしたい。実際の数は、このクエリによって返される行の数によって決まります。

SELECT
  *
FROM
  dbo.MySource
;

したがって、クエリが1行を返す場合、1行をdbo.Groupsに挿入して、生成されたGroupIDを返します。 100行の場合、100行が挿入され、100のIDが一度に生成および返されることを期待します。

1つの明白な方法は、ループで一度に1行を挿入することです。私はそれを避けて、代わりにセットベースのアプローチを使用したいと思います

INSERT INTO
  dbo.GroupID
OUTPUT
  inserted.GroupID INTO @output (ID)
SELECT
  ...  -- what?
FROM
  dbo.MySource
;

単一のステートメントで(できれば)IDENTITY列だけを含むテーブルに複数の行を挿入する方法はありますか?

4
Andriy M

これを書いている時点では、IDENTITYステートメントを使用してINSERT列に複数の行を挿入する方法はありません。 DEFAULT VALUESプレースホルダーは、1行のみを表します。また、INSERT ... SELECT構文には、DEFAULT VALUES句と同じ機能をサポートする拡張機能がありません。

代わりに、MERGEステートメントを使用して目標を達成できます。

MERGE INTO
  dbo.Groups AS tgt
USING
  dbo.MySource AS src  -- << use your source row set here
ON
  1 = 0
WHEN NOT MATCHED THEN
  INSERT DEFAULT VALUES
OUTPUT
  INTO @output (ID)
;

ON 1 = 0句は基本的にMERGEを純粋なINSERTに変換します。これは、明示的にfalseの条件により、すべてのソース行が一致せず、WHEN NOT MATCHED THENブランチがトリガーされるためですステートメントの。これで、WHEN NOT MATCHED THENブランチは単一行の挿入定義を期待します。ここでは、使い慣れたDEFAULT VALUESが完全に有効です。その結果、任意の数の行に対してINSERT ... SELECTの機能を備えたINSERT ... DEFAULT VALUESステートメントを効果的に取得できます。

5
Andriy M