Skip to main content

This is documentation for Caché & Ensemble. See the InterSystems IRIS version of this content.Opens in a new tab

For information on migrating to InterSystems IRISOpens in a new tab, see Why Migrate to InterSystems IRIS?

INSERT OR UPDATE

新規の行または更新をテーブル内の既存の行に追加します。

Synopsis

INSERT OR UPDATE [%NOFPLAN] [restriction] [INTO] table
          SET column1 = scalar-expression1 {,column2 = scalar-expression2} ...  |
          [ (column1{,column2} ...) ] VALUES (scalar-expression1 {,scalar-expression2} ...)  |
          VALUES :array()  |
          [ (column1{,column2} ...) ] query  |
          DEFAULT VALUES

引数

%NOFPLAN オプション — %NOFPLAN キーワードは、Caché がこの操作の凍結されたプラン (ある場合) を無視して、新しいクエリ・プランを生成することを指定します。凍結されたプランは保持されますが、使用されません。 詳細は、“Caché SQL 最適化ガイド” の “凍結プラン” を参照してください。
restriction オプション — %NOLOCK、%NOCHECK、%NOINDEX、%NOTRIGGER のキーワードのうちの 1 つ、またはこれらのキーワードの空白で区切られたリスト。
table 挿入を実行するテーブルまたはビューの名前。この引数はサブクエリでもかまいません。INTO キーワードはオプションです。
column オプション — 列名、または列名のコンマ区切りのリスト。後者の場合は、値のリストに対応した順序で指定します。省略した場合、値のリストは列番号順にすべての列に適用されます。
scalar-expression 対応する column の各フィールドのデータ値を指定するスカラ式またはコンマ区切りのスカラ式のリスト。
:array() 埋め込み SQL のみ — ホスト変数として指定する値の動的なローカル配列。配列の最下位の添え字は指定しないでください。:myupdates():myupdates(5,)、および :myupdates(1,1,) はすべて、有効な指定になります。
query 対応する column の各フィールドに 1 行以上の行のデータ値を指定する、クエリの結果セット。

説明

INSERT OR UPDATE 文は、INSERT 文の拡張です (類似点が多い)。

  • 指定されたレコードが存在しない場合、INSERT OR UPDATEINSERT を実行します。

  • 指定されたレコードが既に存在している場合、INSERT OR UPDATEUPDATE を実行します。この文は指定されたフィールド値でレコードを更新します。指定されたデータが既存のデータと同一である場合でも、更新は行われます。

INSERT OR UPDATE は、UNIQUE KEY フィールド値を既存のデータ値に突き合わせることによって、レコードの存在を判別します。UNIQUE KEY 違反が生じた場合、INSERT OR UPDATE は更新操作を実行します。UNIQUE KEY フィールド値は、INSERT OR UPDATE で明示的に指定された値ではない場合もあります。これは列の既定値または計算された値の結果である場合があります。

単一レコードの INSERT OR UPDATE は、常時 %ROWCOUNT 変数を 1 に設定し、%ROWID 変数を挿入または更新のいずれかが行われた行に設定します。

SELECT 文と組み合わせた INSERT OR UPDATE 文では、複数のテーブル行の挿入または更新、あるいはその両方ができます。詳細は、"INSERT" のリファレンス・ページにある “INSERT クエリ結果” を参照してください。

INSERT OR UPDATE は、同じ構文を使用し、一般に INSERT 文と同じ機能および制限があります。INSERT OR UPDATE の特別な考慮事項については、以下に説明します。ここで特に断りがない限り、詳細は "INSERT" を参照してください。

特権

INSERT OR UPDATE は、SELECT 特権と同様、INSERT 特権および UPDATE 特権の両方が必要です。これらの特権は、表レベルの特権または列レベルの特権のいずれかとして持つ必要があります。

IDKEY のフィールド

IDKEY フィールド値は挿入はできますが、更新はできません。テーブルに IDKEY インデックスと、別の一意のキーの制約がある場合、INSERT OR UPDATE はこれらのフィールドを組み合わせて、挿入または更新のどちらを実行するかを決定します。一方のキーの制約が失敗すると、INSERT OR UPDATE は挿入ではなく更新が強制的に実行されます。ただし、指定された IDKEY フィールドの値が既存の IDKEY フィールドの値と一致しない場合、この更新により IDKEY のフィールドの変更が試行されるので、更新は失敗し、SQLCODE -107 エラーが生成されます。

例えば、テーブル MyTest が、A、B、C、D の 4 つのフィールドと、IDKEY (A,B) および UNIQUE (C,D) の制約で定義されているとします。このテーブルには以下のレコードがあります。

Row 1: A=1, B=1, C=2, D=2
Row 2: A=1, B=2, C=3, D=4

INSERT OR UPDATE ABC (A,B,C,D) VALUES (2,2,3,4) を呼び出します。UNIQUE (C,D) 制約が失敗すると、この文は挿入を実行できなくなるからです。これは代わりに、Row 2 の更新を試行します。Row 2 の IDKEY は (1,2) であり、INSERT OR UPDATE 文はフィールド A の値を 1 から 2 に変更しようとするからです。しかし、IDKEY 値は変更できず、更新は SQLCODE -107 エラーで失敗します。

カウンタ・フィールド

INSERT OR UPDATE を実行する場合、Caché は最初に、操作は挿入であることを前提とします。したがって、SERIAL (%Library.CounterOpens in a new tab) フィールドに整数を指定するために使用される内部カウンタを 1 ずつインクリメントします。挿入では、これらのインクリメントされたカウンタ値を使用して、これらのフィールドに整数値を割り当てます。ただし、Caché は、操作が更新である必要があると判断した場合は、INSERT OR UPDATE は既に内部カウンタをインクリメントしていますが、これらのインクリメントされた整数値をカウンタ・フィールドに割り当てません。このため、次の操作が挿入の場合、これらのフィールドの整数シーケンスにギャップが生じます。詳細は、以下の例を参照してください。

  1. 内部カウンタ値は 4 です。INSERT OR UPDATE は、内部カウンタをインクリメントし、次に行 5 を挿入します:内部カウンタ=5、SERIAL フィールド値=5。

  2. INSERT OR UPDATE は、内部カウンタをインクリメントし、次に既存の行に対して更新を実行する必要があると判断します:内部カウンタ=6、フィールド・カウンタの変更なし。

  3. INSERT OR UPDATE は、内部カウンタをインクリメントし、次に行を挿入します:内部カウンタ=7、SERIAL フィールド値=7。

IDENTITY フィールドと RowID フィールド

RowId の値の割り当てにおける INSERT OR UPDATE の影響は、IDENTITY フィールドが存在するかどうかによって異なります。

  • テーブルに IDENTITY フィールドが定義されていない場合に挿入操作を実行すると、Caché は連続した次の整数値を ID (RowID) フィールドに自動的に割り当てます。更新操作が後続の挿入に影響を与えることはありません。このため、INSERT OR UPDATE は、INSERT と同じ挿入操作を実行します。

  • テーブルに IDENTITY フィールドが定義されている場合に INSERT OR UPDATE を実行すると、Caché は操作が挿入と更新のいずれであるかを判断する前に、IDENTITY フィールドへの整数の指定に使用した内部カウンタを 1 つインクリメントします。挿入操作によって、このインクリメントされたカウンタ値が IDENTITY フィールドに割り当てられます。ただし、Caché は、INSERT OR UPDATE 操作が更新である必要があると判断した場合は、既に内部カウンタをインクリメントしていますが、これらのインクリメントされた整数値を割り当てません。次の INSERT OR UPDATE 操作が挿入の場合、IDENTITY フィールドの整数シーケンスにギャップが生じることになります。RowID フィールド値は、IDENTITY フィールド値から取得されるため、ID (RowID) 整数値の割り当てにギャップが生じることになります。

以下の 5 つの例では、新しいテーブル (SQLUser.CaveDwellers) の作成、INSERT OR UPDATE を使用したこのテーブルへのデータの生成、INSERT OR UPDATE を使用した新しい行の追加および既存の行の更新、SELECT * を使用したデータの表示、およびテーブルの削除が行われています。

以下の例では、CREATE TABLE を使用して、一意のフィールド (Num) が含まれるテーブルを作成しています。

CreateTable
   ZNSPACE "Samples"
   &sql(CREATE TABLE SQLUser.CaveDwellers (
  Num          INT UNIQUE,
  CaveCluster  CHAR(80) NOT NULL,
  Troglodyte   CHAR(50) NOT NULL,
  CONSTRAINT CaveDwellerPK PRIMARY KEY (Num))
  )
  IF SQLCODE=0 {WRITE !,"Table created" }
  ELSEIF SQLCODE=-201 {WRITE !,"Table already exists"}
  ELSE {WRITE !,"CREATE TABLE failed. SQLCODE=",SQLCODE }

以下の例では、クラス定義を使用して、同じテーブルを定義し、Num の一意のキーを定義しています。

   Class SQLUser.CaveDwellers Extends %Persistent [ 
      DdlAllowed,Owner={UnknownUser},SqlRowIdPrivate,
      SqlTableName=CaveDwellers ]
  { 
  Property Num As %Integer;
  Property CaveCluster As %String(MAXLEN=80);
  Property Troglodyte As %String(MAXLEN=50);
  Index UniqueNumIdx On Num [ Type=index,Unique ];
  }
SELECT * FROM SQLUser.CaveDwellers ORDER BY Num

以下の 2 つの例を、任意の順序で 1 回以上実行します。これによりレコード 1 から 5 が挿入されます。レコード 4 が既に存在していれば、INSERT OR UPDATE により更新されます。テーブル・データを表示するには、SELECT * の例を使用します。

InsertOrUpdateIndividualRecords
  ZNSPACE "Samples"
  &sql(INSERT OR UPDATE INTO SQLUser.CaveDwellers (Num,CaveCluster,Troglodyte) VALUES 
    (1,'Bedrock','Flintstone,Fred'))
  IF SQLCODE = 0 { SET rcount=%ROWCOUNT }
  &sql(INSERT OR UPDATE INTO SQLUser.CaveDwellers (Num,CaveCluster,Troglodyte) VALUES 
    (4,'Bedrock','Flintstone,Wilma'))
  IF SQLCODE = 0 { SET rcount=rcount+%ROWCOUNT 
                   WRITE !,rcount," records inserted/updated" }
  ELSE { WRITE !,"Insert/Update failed, SQLCODE=",SQLCODE }
InsertOrUpdateWithQueryResults
   NEW SQLCODE,%ROWCOUNT,%ROWID
  &sql(INSERT OR UPDATE SQLUser.CaveDwellers
      (Num,CaveCluster,Troglodyte)
       SELECT %ID,Home_City,Name
       FROM Sample.Person
       WHERE %ID BETWEEN 2 AND 5)
    IF SQLCODE=0 {
    WRITE !,"Insert/Update succeeded"
    WRITE !,%ROWCOUNT," records inserted/updated"
    WRITE !,"Row ID=",%ROWID }
    ELSE {
    WRITE !,"Insert/Update failed, SQLCODE=",SQLCODE }

以下の例では、テーブルを削除します。

DeleteTable
  ZNSPACE "Samples"
  &sql(DROP TABLE SQLUser.CaveDwellers)
  IF SQLCODE=0 {WRITE !,"Table deleted" }
  ELSEIF SQLCODE=-30 {WRITE !,"Table does not exist"}
  ELSE {WRITE !,"DROP TABLE failed. SQLCODE=",SQLCODE }

関連項目

FeedbackOpens in a new tab