データの挿入

データベースに格納されているテーブルに 1 つまたは複数の行を挿入するため、SQL ステートメントを対話的またはソース コード内で使用することができます。

  • insert メソッド – 一度に 1 行を挿入します。
  • doInsert メソッド – 一度に 1 行を挿入します。
  • insert_recordset ステートメント – 複数のレコードを 1 つまたは複数のテーブルから別のテーブルに 1 回のデータベース トリップで直接コピーします。
  • RecordInsertList.insertDatabase – 1 回のデータベース トリップで複数の行を同時に挿入します。 データをソートする必要がない場合は、この構文を使用します。
  • RecordSortedList.insertDatabase – 1 回のデータベース トリップで複数の行を同時に挿入します。 特定のテーブルのデータのサブセットを必要とし、現在インデックスとして存在しない順序でソートする場合は、このコンストラクトを使用します

RecordSortedListRecordInsertList、および insert_recordset を使用すると、複数のレコードを挿入できます。 これらのメソッドを使用することにより、アプリケーションとデータベース間の通信が減少します。 したがって、パフォーマンスの向上に役立ちます。 場合によっては、レコードのセットに基づく操作をレコードごとの操作に戻すことができます。 詳細については、セット ベースからレコード単位への操作の変換を参照してください。

insert メソッド

insert メソッドは、一度に 1 つのレコードを挿入します。 RecId フィールドおよびシステム フィールドの値を生成し、バッファーの内容 (つまり、列の値) をデータベースに挿入します。

  • insert メソッドを呼び出す前に、テーブル変数で select ステートメントを使用しないでください。
  • insert メソッドでは、すべての主要なフィールド要件とテーブルの依存関係を処理するわけではありません。 それらの処理を行うには、コードを記述する必要があります。

挿入メソッドが作用する方法を次に示します。

  • クエリによって選択されている行の指定された列のみ、名前付きテーブルに挿入されます。
  • コピー元のテーブルの列とコピー先のテーブルの列は、互換性のある型であることが必要です。
  • 両方のテーブルの列がタイプおよび順序において一致する場合、列リストは挿入句から省略されます。

次の例では、新しいレコードを CustGroup テーブルに挿入します。 新しいレコードの CustGroup 列は 41 に設定されています。 レコードの他のフィールドは空白になります。

CustGroup custGroup;
ttsBegin;
custGroup.CustGroup = '41';
custGroup.insert();
ttsCommit;

insert メソッドの動作を上書きするには、doInsert メソッドを使用します。

doInsert メソッド

doInsert メソッドは、RecId フィールドおよびその他のシステム フィールドの値を生成した後、データベースにバッファーの内容を挿入します。 テーブルの insert メソッドをバイパスする必要がある場合は、このメソッドを使用します。

警告

doInsert の呼び出しは、データベース イベント ハンドラー (たとえば oninserting および oninserted)、コマンド チェーン onInsert()、および insert() の呼び出し自体を含むすべてのロジックをスキップします。 一般に、doInsert を使用することは不適切なプラクティスと見なされており、使用することはお勧めしません。

insert_recordset ステートメント

insert_recordset ステートメントは、1 回のサーバー トリップで、1 つ以上のソース テーブルからデータを直接 1 つのターゲット テーブルにコピーします。 配列挿入 (RecordInsertList.insertDatabase または RecordSortedList.insertDatabase) より insert_recordset を使用する方が高速です。 ただし、配列挿入は、データを挿入する前に処理する場合より柔軟になります。 insert_recordset は、一度に複数のレコードに対して操作を実行するレコード セット ベースの演算子ですが、多くの場合、レコードごとの操作に戻すことができます。 詳細については、セット ベースからレコード単位への操作の変換を参照してください。

次の insert_recordset ステートメントの構文では、かっこ ([]) はステートメントのオプションの要素を示します。

insert_recordsetDestinationTable(ListOfFields)

selectListOfFields1fromSourceTable[ whereWhereClause]

[ joinListOfFields2fromJoinedSourceTable[ whereJoinedWhereClause]]

  • ListOfFields 出力先テーブルは、ソース テーブル内のフィールドのリストと一致する必要があります。 データは、フィールドの一覧に表示されている順に転送されます。 フィールドの一覧に表示されていない出力先テーブルのフィールドは、他の領域と同じように、0 (ゼロ) の値に割り当てられています。 RecId などのシステム フィールドは、出力先テーブルのカーネルによって透過的に割り当てられます。
  • WhereClause および JoinedWhereClause は、select ステートメントの WhereClause 句で説明されています。

insert_recordset: 別のテーブルからのデータの挿入

この例では、NameValuePair テーブルの列は名前値ごとに合計されます。 集計の結果は、ValueSumByName テーブルに格納されます。

ValueSumByName valueSumName;
NameValuePair nameValuePair;

insert_recordset valueSumName (Name, ValueSum)
    select Name, sum(Value)
    from nameValuePair
    group by Name;

insert_recordset: 変数からのデータの挿入

次の例は、insert_recordset ステートメントが変数データを挿入できることを示しています。

  • 1 つの新しいレコードだけを挿入する場合は、firstonly キーワードを含めます。 firstonly を省略すると CustTable テーブルの各レコードに対してレコードが挿入されます。
  • 128 または "このリテラル文字列" などのリテラルは、挿入されたデータのソースとしてクエリで使用できません。
  • ソース テーブルの列は、ターゲット テーブルに対応している必要はありません。

この例では、NameValuePair テーブルに 1 つの新しいレコードが挿入されます。 このレコードの ID 値は 1名前の値は Name1の値は 1 です。

NameValuePair nameValuePair;
CustTable custTable;

int id_var = 1;
str name_var = 'Name1';
int value_var = 1;

insert_recordset nameValuePair (Id, Name, Value)
select firstonly id_var, name_var, value_var from custTable;

insert_recordset: 結合を使用してデータを挿入する

次の例は、サブセレクトを持つ insert_recordset ステートメント上の 3 つのテーブルの結合を示しています。 また、同じ結合がある while select ステートメントも示しています。 変数は、1 つの列に挿入された値を供給するために使用されます。 str 変数は、宣言する必要があり、対応するデータベース フィールドの最大長さ以下の長さである必要があります。

この例では、tabEmplProj5 テーブルに対する insert_recordset ステートメントがあります。 ターゲット フィールドの 1 つに説明という名前が付けられ、そのデータはローカル sDescriptionVariable 変数から取得されます。 説明フィールドの構成キーは無効の場合でも insert_recordset ステートメントは成功します。 システムでは、Description フィールドと sDescriptionVariable 変数の両方を無視します。 したがって、このコードはコンフィギュレーション キーの自動化の例を提供します。 コンフィギュレーション キーの自動化は、コンフィギュレーション キーがオフになっているフィールドにデータを挿入する insert_recordset ステートメントの動作を、システムが自動的に調整できるときに発生します。

static void InsertJoin42Job(Args _args)
{
    GmTabDepartment tabDept2;
    GmTabEmployee tabEmpl3;
    GmTabProject tabProj4;
    GmTabEmployeeProject tabEmplProj5;
    str 64 sDescriptionVariable = "From variable.";
    delete_from tabEmplProj5;
    insert_recordset tabEmplProj5
        (  Description
        , EmployeeRecId
        , ProjectRecId
        )
    select sDescriptionVariable, RecId
    from tabEmpl3
        join tabDept2
            where tabEmpl3 .DepartmentGuid == tabDept2 .DepartmentGuid
        join RecId from tabProj4
            where tabDept2 .DepartmentGuid == tabProj4 .DepartmentGuid;
    info(strFmt("%1 == Number of rows inserted.", tabEmplProj5.rowCount()));        
    
    while select tabEmplProj5
        join tabEmpl3
            where tabEmplProj5.EmployeeRecId == tabEmpl3.RecId
        join tabProj4
            where tabEmplProj5.ProjectRecId == tabProj4.RecId
    {
        info(
            tabEmpl3 .EmployeeName
            + "  --works on--  "
            + tabProj4 .ProjectName
            + " (" + tabEmplProj5 .Description + ")."
            );
    }

/*****************  Actual Infolog output
Message (01:05:41 pm)
4 ==Number of rows inserted.
Alice  --works on--  Project ZZZ (From variable.).
Alice  --works on--  Project YY (From variable.).
Beth  --works on--  Project ZZZ (From variable.).
Beth  --works on--  Project YY (From variable.).
*****************/
}

DuplicateKeyException 例外の処理

次の例は、明示的なトランザクションのコンテキストで DuplicateKeyException 例外をキャッチする方法を示しています。 キー値が既に存在しているため、xRecord.insert の呼び出しが失敗した場合に例外がスローされます。 catch ブロックでは、コードで修正アクションを実行するか、後で分析するためにエラーを記録したりできます。 これにより、トランザクションの保留中のすべての作業が失うことなく、コードの実行を続けることできます。 insert_recordset などのセット ベース操作によって発生する DuplicateKeyException 例外を把握することはできません。

この例は、SourceTable および DestinationTable という 2 つのテーブルによって異なります。 各テーブルには 1 つの必須の整数フィールドがあります。 フィールドの名前はそれぞれ、SourceKeyField および DestinationKeyField です。 固有インデックスは、各キー フィールドで定義されます。 SourceTable テーブルには、少なくとも 1 つのレコードが必要です。

static void JobDuplicKeyException44Job(Args _args)
{
    SourceTable      sourceTable; // Must have at least one record.
    DestinationTable destinationTable;
    int countTries = 0;
    int numberAdjust = 0;
    int newKey;
    int inote;
    container notes;

    // Empty the destination table.
    delete_from destinationTable;

    // Copy all the records from SourceTable to DestinationTable
    insert_recordset destinationTable (destinationKeyField)
        select SourceKeyField from sourceTable order by SourceKeyField asc;

    // Copy the records from SourceTable to DestinationTable, one at a time.
    // This immediately throws a DuplicateKeyException.
    ttsBegin;
    try
    {
        countTries++;
        notes += strFmt("Inside the try block, try count is %1.", countTries);
        while select sourceTable 
            order by SourceKeyField asc
        {
            destinationTable.clear();
            newKey = sourceTable.SourceKeyField + numberAdjust;
            destinationTable.DestinationKeyField = newKey;
            notes += strFmt("%1 is the key to be tried." , newKey);
            destinationTable.insert();
            notes += "Success: .insert()";
        }
        ttsCommit;
    }
    catch (Exception::DuplicateKeyException, destinationTable) // Table is optional.
    {
        notes += "Inside the catch block.";
        notes += 'Error: ' + infolog.text().strReplace('\n', '');
        if (countTries <= 1)
        {
            notes += "Will issue retry.";
            numberAdjust = 1;
            retry; // Erases Infolog.
        }
        else
        {
            notes += "Aborting the transaction.";
            ttsAbort;
        }
    }

    for (inote = 1; inote <= conLen(notes); inote++)
    {
        info(conPeek(notes, inote));
    }
}

/* Output
    ---- Inside the try block, try count is 1.
    ---- 11 is the key to be tried.
    ---- Inside the catch block.
    Cannot create a record in DestinationTable (DestinationTable).
    The record already exists.
    ---- Will issue retry.
    ---- Inside the try block, try count is 2.
    ---- 12 is the key to be tried.
    ---- .insert() successful.
*/