Learning
Community
Open Exchange
Global Masters
InterSystems IRIS Data Platform 2019.4 / Application Development / InterSystems SQL Reference / SQL Commands / INSERT
Previous section   Next section

INSERT

Adds a new row (or rows) to a table.

Synopsis

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

Arguments

%keyword Optional — One or more of the following keyword options, separated by spaces: %NOCHECK, %NOFPLAN, %NOINDEX, %NOLOCK, %NOTRIGGER, %PROFILE, %PROFILE_ALL.
table The name of the table or view on which to perform the insert operation. This argument may be a subquery. The INTO keyword is optional. A table name (or view name) can be qualified (schema.table), or unqualified (table). An unqualified name is matched to its schema using either a schema search path (if provided) or the default schema name.
column Optional — A column name or comma-separated list of column names that correspond in sequence to the supplied list of values. If omitted, the list of values is applied to all columns in column-number order.
scalar-expression A scalar expression or comma-separated list of scalar expressions that supplies the data values for the corresponding column fields.
:array() Embedded SQL only — A dynamic local array of values specified as a host variable. The lowest subscript level of the array must be unspecified. Thus :myupdates(), :myupdates(5,), and :myupdates(1,1,) are all valid specifications.
query A SELECT query the result set of which supplies the data values for the corresponding column fields for one or multiple new rows.

Description

The INSERT statement can be used in two ways:
  • A single-row INSERT adds one new row to a table. It inserts data values for all specified columns (fields) and defaults unspecified column values to either NULL or the defined default value. It sets the %ROWCOUNT variable to the number of affected rows (always either 1 or 0).
  • An INSERT with a SELECT adds multiple new rows to a table. It inserts data values for all specified columns (fields) for each row from the query result set and defaults unspecified column values to either NULL or the defined default value. This use of an INSERT statement combined with a SELECT query is commonly used to populate a table with existing data extracted from other tables, as described in the “INSERT Query Results” section below.
This reference page is structured as follows:

INSERT OR UPDATE

The INSERT OR UPDATE statement is a variant of the INSERT statement that performs both insert and update operations. First it attempts to perform an insert operation. If the insert request fails due to a UNIQUE KEY violation (for the field(s) of some unique key, there exists a row that already has the same value(s) as the row specified for the insert), then it automatically turns into an update request for that row, and INSERT OR UPDATE uses the specified field values to update the existing row.
INSERT OR UPDATE does not support Fast Insert.

%Keyword Options

To use a %keyword option argument, you must have the corresponding admin-privilege for the current namespace. Refer to GRANT for further details.
Specifying %keyword argument(s) restricts processing as follows:
  • %NOCHECK — foreign key referential integrity checking is not performed. Column data validation for data type, maximum length, data constraints, and other validation criteria is also not performed. The WITH CHECK OPTION validation for a view is not performed when performing an INSERT through a view.
    Note:
    Because use of %NOCHECK can result in invalid data, this %keyword argument should only be used when performing bulk inserts or updates from a reliable data source.
  • %NOFPLAN — the frozen plan (if any) is ignored for this operation; the operation generates a new query plan. The frozen plan is retained, but not used. For further details, refer to Frozen Plans in SQL Optimization Guide.
  • %NOINDEX — the index maps are not set during INSERT processing.
  • %NOLOCK — the row is not locked upon INSERT. This should only be used when a single user/process is updating the database.
  • %NOTRIGGER — the base table insert triggers are not pulled during INSERT processing.
  • %PROFILE or %PROFILE_ALL — if one of these keyword directives is specified, SQLStats collecting code is generated. This is the same code that would be generated with PTools turned ON. The difference is that SQLStats collecting code is only generated for this specific statement. All other SQL statements within the routine/class being compiled will generate code as if PTools is turned OFF. This enables the user to profile/inspect specific problem SQL statements within an application without collecting irrelevant statistics for SQL statements that are not being investigated. For further details, refer to SQL Runtime Statistics in the InterSystems SQL Optimization Guide.
    %PROFILE collects SQLStats for the main query module. %PROFILE_ALL collects SQLStats for the main query module and all of its subquery modules.
You can specify multiple %keyword arguments in any order. Multiple arguments are separated by spaces.

Table Argument

You can specify the table argument to insert into a table directly, insert through a view, or insert via a subquery. Inserting through a view is subject to requirements and restrictions, as described in CREATE VIEW. The following is an example of an INSERT using a subquery in place of the table argument:
INSERT INTO (SELECT field1 AS ff1 FROM MyTable) (ff1) VALUES ('test')
The subquery target must be updateable, following the same criteria used to determine if a view's query is updateable. Attempting to INSERT using a view or a subquery that is not updateable generates an SQLCODE -35 error.
You cannot specify a table-valued function or JOIN syntax in the table argument.
For required table privileges, refer to Privileges. For error codes, refer to SQLCODE Errors.

Value Assignment

This section describes how data values are assigned to columns (fields) during an INSERT operation:
If you omit the column list argument, the INSERT assumes all columns are to be inserted, in column number order. If you specify a column list, the individual values must correspond positionally with the column names in the column list.

Value Assignment Syntax

When inserting a record, you can assign values to specified columns in a variety of ways. All non-specified columns must either accept NULL by default or have a defined default value.
  • Using the SET keyword, specify one or more column = scalar-expression pairs as a comma-separated list. For example:
    SET StatusDate='05/12/06',Status='Purged'
    
  • Using the VALUES keyword, specify a list of columns equated to a corresponding scalar-expressions list. For example:
    (StatusDate,Status) VALUES ('05/12/06','Purged')
    
    When assigning scalar-expression values to a column list, there must be a scalar-expression for each specified column.
  • Using the VALUES keyword without a column list, specify a list of scalar-expressions that implicitly correspond to the columns of the row in column order. For example:
    VALUES ('Fred Wang',65342,'22 Main St. Anytown MA','123-45-6789')
    
    Values must be specified in column number order. You must specify a value for every base table column that takes a user-supplied value; an INSERT using column order cannot take defined field default values. The RowID column cannot be user-specified, and is therefore not included in this syntax.
  • Using the VALUES keyword without a column list, specify a dynamic local array of scalar-expressions that implicitly correspond to the columns of the row in column order. For example:
    VALUES :myarray()
    
    This value assignment can only be performed from Embedded SQL using a host variable. Unlike all other value assignments, this usage allows you to delay specifying which columns are to be inserted until runtime (by populating the array at runtime). All other types of insert require that you specify which columns are to be inserted at compile time. This syntax cannot be used with a linked table; attempting to do so results in an SQLCODE=-155 error.
    Values must be specified in column number order. You must specify a value for every base table column that takes a user-supplied value; an INSERT using column order cannot take defined field default values. Supplied array values must begin with array(2). Column 1 is the RowID field; you cannot specify a value for the RowID field. For further details, see “Host Variable as a Subscripted Array” in the “Using Embedded SQL” chapter of Using InterSystems SQL.
If you specify column names and corresponding data values, you can omit columns for which there is a defined default value or which accept NULL. An INSERT can insert a default value for most field data types, including stream fields.
If you do not specify column names, data values must correspond positionally to the defined column list. You must specify a value for every user-specifiable base table column; defined default values cannot be used. (You can, of course, specify an empty string as a column value.)
To list all of the column names and column numbers defined for a specified table, refer to Column Names and Numbers in the “Defining Tables” chapter of Using InterSystems SQL.
For required column privileges, refer to Privileges. For error codes, refer to SQLCODE Errors.

DISPLAY to LOGICAL Data Conversion

Data is stored in LOGICAL mode format. For example, a date is stored as an integer count of days. Input data that is not in LOGICAL mode format must be converted to LOGICAL mode format. Compiled SQL supports automatic conversion of input values from DISPLAY or ODBC format to LOGICAL format. Automatic conversion of input data requires two factors: when compiled, the SQL must specify RUNTIME mode; when executed, the SQL must execute in a LOGICAL mode environment.
  • In Embedded SQL, if you specify #SQLCompile Select=runtime, InterSystems IRIS will compile the SQL statement with code that converts input values from a display format to LOGICAL mode storage format. InterSystems IRIS performs this mode conversion both for single values and for arrays of values. For further details, see #SQLCompile Select in the “ObjectScript Macros and the Macro Preprocessor” chapter of Using ObjectScript.
  • In an SQL CREATE FUNCTION, CREATE METHOD, or CREATE PROCEDURE statement, if you specify SELECTMODE RUNTIME, InterSystems IRIS will compile the SQL statement with code that converts input values from a display format to LOGICAL mode storage format.
The input data may be in any format: DISPLAY format (for example, 2/22/2018), ODBC format (for example, 2018-02-22), or LOGICAL format (for example, 64701). The data is stored in LOGICAL format if the SQL execution environment is in LOGICAL mode. This is the default mode for all InterSystems SQL execution environments.
You can explicitly set the select mode to LOGICAL in SQL execution environments as follows:

%SerialObject Properties

When inserting data into a %SerialObject, you must insert into the table (persistent class) that references the embedded %SerialObject; you cannot insert into a %SerialObject directly. From the referencing table, you can either:
  • Use the referencing field to insert values for multiple %SerialObject properties as a %List structure. For example, if the persistent class has a property PAddress that references a serial object contain the properties Street, City, and Country (in that order), you insert SET PAddress=$LISTBUILD('123 Main St.','Newtown','USA'). The %List must contain values for the properties of the serial object (or placeholder commas) in the order that these properties are specified in the serial object.
  • Use underscore syntax to insert values for individual %SerialObject properties in any order. For example, if the persistent class has a property PAddress that references a serial object contain the properties Street, City, and Country, you insert SET PAddress_City='Newtown',PAddress_Street='123 Main St.',PAddress_Country='USA'. Unspecified serial object properties default to NULL.

Non-Display Characters

You can insert non-display characters using the CHAR function and the concatenation operator. For example, the following example inserts a string consisting of the letter “A”, a line feed, and the letter “B”:
INSERT INTO MyTable (Text) VALUES ('A'||CHAR(10)||'B')
Note that to concatenate the results of a function you must use the || concatenation operator, not the _ concatenation operator.
A query can determine if a non-display character is present using the LENGTH or $LENGTH function.

Special Variables

You can insert into a column the value of the following special variables:
A %TABLENAME, or %CLASSNAME pseudo-field variable keyword. %TABLENAME returns the current table name. %CLASSNAME returns the name of the class corresponding to the current table.
One or more of the following ObjectScript special variables (or their abbreviations): $HOROLOG, $JOB, $NAMESPACE, $TLEVEL, $USERNAME, $ZHOROLOG, $ZJOB, $ZNSPACE, $ZPI, $ZTIMESTAMP, $ZTIMEZONE, $ZVERSION.

Stream Data

You can insert the following types of data values into a stream field:
  • An object reference (OREF) to a stream object. InterSystems IRIS opens this object and copies its contents into the new stream field. For example:
        set oref=##class(%Stream.GlobalCharacter).%New()
        do oref.Write("Technique 1")
    
        //do the insert; use an actual OREF
        &sql(INSERT INTO MyStreamTable (MyStreamField) VALUES (:oref))
    
  • A string version of an OREF of a stream, for example:
        set oref=##class(%Stream.GlobalCharacter).%New()
        do oref.Write("Technique 2")
    
        //next line converts OREF to a string OREF
        set string=oref_""
    
        //do the insert
        &sql(INSERT INTO MyStreamTable (MyStreamField) VALUES (:string))
    
  • A numeric value, such as 1 or -1.
  • A string literal whose first character is not numeric, for example:
        set literal="Technique 3"
    
        //do the insert; use a string
        &sql(INSERT INTO MyStreamTable (MyStreamField) VALUES (:literal))
    
    If the first character is numeric, SQL interprets the literal as the string form of an OREF instead. For example, the value 2@User.MyClass would be considered the string version of an OREF, and not a string literal.
Attempting to insert an improperly defined stream value results in an SQLCODE -412 error: General Stream Error.

List Structured Data

InterSystems IRIS supports the list structure data type %List (data type class %Library.List). This is a compressed binary format, which does not map to a corresponding native data type for InterSystems SQL. It corresponds to data type VARBINARY with a default MAXLEN of 32749. For this reason, Dynamic SQL cannot use INSERT or UPDATE to set a property value of type %List. For further details, refer to the Data Types reference page in this manual.

Insert Counter Values

A table can optionally have one field defined as IDENTITY. By default, this field receives an integer from an automatically incremented table counter whenever a row is inserted into the table. By default, an insert cannot specify a value for this field. However, this default is configurable. An IDENTITY field value cannot be modified by an update operation. This counter is reset by a TRUNCATE TABLE operation.
A table can optionally have one field defined as data type ROWVERSION. If this field is defined, an insert operation automatically inserts an integer from the namespace-wide RowVersion counter into this field. An update operation automatically updates this integer with the current namespace-wide RowVersion counter value. No user-specified, calculated, or default value can be inserted for a ROWVERSION field. This counter cannot be reset.
A table can optionally have one or more fields defined as data type SERIAL (%Library.Counter). By default, this field receives an integer from an automatically incremented table counter whenever a row is inserted into the table. However, a user can specify an integer value for this field during an insert, overriding the table counter default. A SERIAL (%Counter) field value cannot be modified by an update operation. This counter is reset by a TRUNCATE TABLE operation.

Inserting SERIAL Values

An INSERT operation can specify one of the following values for a field with the SERIAL data type, with the following results:
  • No value, 0 (zero), or a nonnumeric value: InterSystems IRIS ignores the specified value, and instead increments this field's current serial counter value by 1, and inserts the resulting integer into the field.
  • A positive integer value: InterSystems IRIS inserts the user-specified value into the field, and changes the serial counter value for this field to this integer value.
Thus a SERIAL field contains a series incremental integer values. These values are not necessarily continuous or unique. For example, the following is a valid series of values for a SERIAL field: 1, 2, 3, 17, 18, 25, 25, 26, 27. Sequential integers are either InterSystems IRIS-generated or user-supplied; nonsequential integers are user-supplied. If you wish SERIAL field values to be unique, you must apply a UNIQUE constraint on the field.

Insert Computed Values

A field defined with COMPUTECODE may insert a value as part of the INSERT operation, unless the field is CALCULATED. If you supply a value for a COMPUTED field or if this field has a default value, INSERT stores this explicit value. Otherwise, the field value is computed, as follows:
  • COMPUTECODE: value is computed and stored upon INSERT, value is not changed upon UPDATE.
  • COMPUTECODE with COMPUTEONCHANGE: value is computed and stored upon INSERT, is recomputed and stored upon UPDATE.
  • COMPUTECODE with DEFAULT and COMPUTEONCHANGE: default value is stored upon INSERT, value is computed and stored upon UPDATE.
  • COMPUTECODE with CALCULATED or TRANSIENT: you cannot INSERT a value for this field because no value is stored. The value is computed when queried. However, InterSystems IRIS does perform validation on this field as part of the insert operation:
    • If you attempt to insert a value into a calculated field, InterSystems IRIS performs validation on the supplied value and issues an error if the value is invalid. If the value is valid, InterSystems IRIS proceeds with the row insert: it does not insert the value in this field, issues no SQLCODE error, and increments ROWCOUNT.
    • If a field of this type is part of a foreign key constraint, a value for this field is computed during the insert in order to perform the referential integrity check; this computed value is not stored.
If the compute code contains a programming error (for example, divide by zero), the INSERT operation fails with an SQLCODE -415 error.
For further details, refer to Computing a field value on INSERT or UPDATE.

DEFAULT VALUES Clause

You can insert a row into a table that has all of its field values set to default values. Fields that have a defined default value are set to that value. Fields without a defined default value are set to NULL. This is done using the following command:
INSERT INTO Mytable DEFAULT VALUES
Fields defined with the NOT NULL constraint and no defined DEFAULT fail this operation with an SQLCODE -108.
Fields defined with the UNIQUE constraint can be inserted using this statement. If a field is defined with a UNIQUE constraint and no DEFAULT value, repeated invocations insert multiple rows with this UNIQUE field set to NULL. If a field is defined with a UNIQUE constraint and a DEFAULT value, this statement can only be used once. A second invocation fails with an SQLCODE -119.
DEFAULT VALUES inserts a row with a system-generated integer values for counter fields. These include the RowID, and the optional IDENTITY field, SERIAL (%Counter) field, and ROWVERSION field.

Insert Query Results: INSERT with SELECT

A single INSERT can be used to insert multiple rows into a table by combining it with a SELECT statement. Any valid SELECT query can be used. The SELECT extracts column data from one or more tables and the INSERT creates corresponding new rows in its table containing this column data. Corresponding fields may have different column names and column lengths, so long as the inserted data can fit in the insert table field. Corresponding fields must pass data type and length validation; otherwise an SQLCODE -104 error is generated.
You can limit the number of rows inserted by specifying a TOP clause in the SELECT statement. You can also use an ORDER BY clause in the SELECT statement to determine which rows will be selected by the TOP clause.
An INSERT with SELECT operation sets the %ROWCOUNT variable to the number of rows inserted (either 0 or a positive integer).
The following example uses two embedded SQL programs to show this use of INSERT. The first example uses CREATE TABLE to create a new table SQLUser.MyStudents, and the second example populates this table with data extracted from Sample.Person. (Alternatively, you can create a new table from an existing table definition and insert data from the existing table in a single operation using the $SYSTEM.SQL.QueryToTable() method.)
To demonstrate this, please run the first embedded SQL program, then run the second. (It is necessary to use two embedded SQL programs here because embedded SQL cannot compile an INSERT statement unless the referenced table already exists.)
The following program creates the MyStudents table with two stored data fields, and one calculated field:
   WRITE !,"Creating table"
  &sql(CREATE TABLE SQLUser.MyStudents (
    StudentName VARCHAR(32),
    StudentDOB DATE,
    StudentAge INTEGER COMPUTECODE {SET {StudentAge}=
                       $PIECE(($PIECE($H,",",1)-{StudentDOB})/365,".",1)}
                       CALCULATED )
    )
  IF SQLCODE=0 {
    WRITE !,"Created table, SQLCODE=",SQLCODE }
  ELSEIF SQLCODE=-201 {
    WRITE !,"Table already exists, SQLCODE=",SQLCODE }
The following program uses INSERT to populate the MyStudents table with query results. Because the StudentAge field is calculated you cannot supply a value to this field; its value is calculated each time the MyStudents table is queried:
  WRITE !,"Populating table with data"
  NEW SQLCODE,%ROWCOUNT,%ROWID
  &sql(INSERT INTO SQLUser.MyStudents (StudentName,StudentDOB)
     SELECT Name,DOB
     FROM Sample.Person WHERE Age <= '21')
  IF SQLCODE=0 {
    WRITE !,"Number of records inserted=",%ROWCOUNT
    WRITE !,"Row ID of last record inserted=",%ROWID }
  ELSE {
    WRITE !,"Insert failed, SQLCODE=",SQLCODE }
Note that executing this INSERT program multiple times will succeed, but produces generally undesirable results. Each execution populates SQLUser.MyStudents with another set of records (%ROWCOUNT) with identical Name and DOB field values, automatically assigning each record a unique RowID value.
To display the data, go to the Management Portal, select the Globals option for the desired namespace. Scroll to “SQLUser.MyStudentsD” and click the Data option.
The following programs display the MyStudents table data, then delete this table:
SELECT * FROM SQLUser.MyStudents ORDER BY StudentAge
  &sql(DROP TABLE SQLUser.MyStudents)
  IF SQLCODE=0 {WRITE !,"Table deleted" }
  ELSE {WRITE !,"SQLCODE=",SQLCODE," ",%msg }
By default, an Insert Query Results operation is an atomic operation. Either all of the specified rows are inserted in a table, or none of the rows are inserted. For example, if inserting one of the specified rows would violate foreign key referential integrity, the INSERT fails and no rows are inserted. This default is modifiable, as described below.

Copying Data into a Duplicate Table

You can use INSERT with SELECT * to copy the data from a table to a duplicate table, as long as the column order matches and the data types are compatible. The column names do not have to match.
INSERT INTO Sample.DupTable SELECT * FROM Sample.SrcTable
  • Data type compatible with data values: You can, for example, insert integer data from an INTEGER field into a VARCHAR field, or from a VARCHAR field into an INTEGER field. The INSERT would fail with an SQLCODE -104 if any data value was incompatible with the destination data type. You can use the CONVERT function to convert inserted data to the destination data type.
  • Data type length compatible with data values: The defined column data lengths do not have to match each other, they just have to match the actual data. For example, SrcTable can have a column FullName VARCHAR(60) and DupTable can have a corresponding PersonName VARCHAR(40). The INSERT will succeed as long as no existing FullName value is longer than 40 characters. The INSERT would fail with an SQLCODE -104 if any FullName value was longer than 40 characters.
  • Compatible column order: The two tables must have the same column order. Otherwise an SQLCODE -64 error is generated. The DDL CREATE TABLE operation lists the columns in the order defined. A persistent class that defines a table lists the columns in alphabetical order.
  • Compatible column count: The destination table can have additional columns beyond the ones copied. For example, SrcTable can have the columns FullName VARCHAR(60),Age INTEGER and DupTable can have PersonName VARCHAR(60),Years INTEGER,ShoeSize INTEGER. However, note that a persistent class that defines a table lists the columns in alphabetical order.
  • Private RowID: Both tables must have the ID (RowID) field defined as private (hidden). Otherwise, this operation fails with an SQLCODE -111. The DDL CREATE TABLE operation defines the RowID as private by default. A persistent class that defines a table defines the RowID as public by default; you must specify the SqlRowIdPrivate class keyword. Whether or not one of the tables is Final has no effect on copying data into a duplicate table.
This operation can be used to copy existing data into a redefined table that will accept future column data values that would not have been valid in the original table.

SQLCODE Errors

By default, an INSERT is an all-or-nothing event: either the row (or rows) is inserted completely or not at all. InterSystems IRIS returns a status variable SQLCODE, indicating the success or failure of the INSERT. To insert a row into a table, the insert must meet all table, field name, and field value requirements, as follows.
Tables:
  • The table must already exist. Attempting an insert to a nonexistent table results in an SQLCODE -30 error. Because INSERT checks for the table's existence at compile time, a single compiled SQL program (such as an Embedded SQL program) cannot create a table (using CREATE TABLE) and then insert values into it.
  • The table cannot be defined as READONLY. Attempting to compile an INSERT that references a ReadOnly table results in an SQLCODE -115 error. Note that this error is issued at compile time, rather than at execution time. See the description of READONLY objects in the Other Options for Persistent Classes chapter of Defining and Using Classes.
  • If updating a table through a view, the view cannot be defined as WITH READ ONLY. Attempting to do so results in an SQLCODE -35 error. If the view is based on a sharded table, you cannot INSERT through a view defined WITH CHECK OPTION. Attempting to do so results in an SQLCODE -35 with the %msg INSERT/UPDATE/DELETE not allowed for view (sample.myview) based on sharded table with check option conditions. See the CREATE VIEW command for further details.
  • You must have appropriate privileges to insert to a table.
Field Names:
  • The field must exist. Attempting an insert to a nonexistent field results in an SQLCODE -29 error. To list all of the field names defined for a specified table, refer to Column Names and Numbers in the “Defining Tables” chapter of Using InterSystems SQL.
  • The insert must specify all required fields. Attempting to insert a row without specifying a value for a required field results in an SQLCODE -108 error.
  • The insert cannot include duplicate field names. Attempting to insert a row containing two fields with the same name results in an SQLCODE -377 error.
  • The insert cannot include fields that are defined as READONLY. Attempting to compile an INSERT that references a READONLY field results in an SQLCODE -138 error. Note that this error is now issued at compile time, rather than only occurring at execution time. When you link a table using the Link Table Wizard, you have the option of defining fields as Read Only. The field on the source system might not be read only, but if IRIS defines the linked table's field as Read Only, attempting an INSERT that references this field results in an SQLCODE -138 error.
Field Values:
  • Every field value must pass data type validation. Attempting to insert a field value inappropriate to the field data type results in an SQLCODE -104 error. Note that this applies only to a inserted data value; a field’s DEFAULT value, if taken, does not have to pass data type validation or data size validation.
    • Data Type Mismatch: The field’s data type, not the type of the inserted data, determines appropriateness. For example, attempting to insert a string data type value into a date field fails unless the string passes date validation for the current mode; however, attempting to insert a date data type value into a string field succeeds, inserting the date as a literal string. You can use the CONVERT function to convert data to the destination data type.
    • Data Size Mismatch: A data value must be within the MAXLEN, MAXVAL, and MINVAL for the field. For example, attempting to insert a string longer than 24 characters into a field defined as VARCHAR(24), or attempting to insert a number larger than 127 into a field defined as TINYINT result an SQLCODE -104 error.
    • Numeric Type Mismatch: If an invalid DOUBLE number is supplied via ODBC or JDBC an SQLCODE -104 error occurs.
  • Every field value must pass data value validation:
    • A field defined as NOT NULL must be provided with a data value. If there is no DEFAULT value, not specifying a data value results in an SQLCODE -108 error, indicating that you have not specified a required field.
    • A field value must obey uniqueness constraints. Attempting to insert a duplicate field value in a field (or group of fields) with a uniqueness constraint results in an SQLCODE -119 error. This error is returned if the field has a UNIQUE data constraint, or if the unique fields constraint has been applied to a group of fields. This error can occur when you specify a duplicate value to a unique field, or to a primary key field, or when you do not specify a value and a second use of the field’s DEFAULT would supply a duplicate value. The SQLCODE -119 %msg string includes both the field and the value that violate the uniqueness constraint. For example <Table 'Sample.MyTable', Constraint 'MYTABLE_UNIQUE3', Field(s) FullName="Molly Bloom"; failed unique check> or <Table 'Sample.MyTable', Constraint 'MYTABLE_PKEY2', Field(s) FullName="Molly Bloom"; failed unique check>. For details on listing a table’s unique value and primary key field constraints and the naming of constraints, refer to Catalog Details: Constraints.
    • A field defined as a persistent class property with the VALUELIST parameter can only accept as a valid value one of the values listed in VALUELIST, or be provided with no value (NULL). VALUELIST valid values are case-sensitive. Specifying a data value that doesn’t match the VALUELIST values results in an SQLCODE -104 field value failed validation error.
  • Numbers are inserted in canonical form, but can be specified with leading and trailing zeros and multiple leading signs. However, in SQL, two consecutive minus signs are parsed as a single-line comment indicator. Therefore, attempting to specify a number with two consecutive leading minus signs results in an SQLCODE -12 error.
  • By default, an insert cannot specify values for fields for which the value is system-generated, such as the RowID, IDKey, or IDENTITY field. By default, attempting to insert a non-NULL field value for any of these fields results in an SQLCODE -111 error. Attempting to insert a NULL for one of these fields causes InterSystems IRIS to override the NULL with a system-generated value; the insert completes successfully and no error code is issued.
    If a field of data type ROWVERSION is defined, it is automatically assigned a system-generated counter value when a row is inserted. Attempting to insert a value into a ROWVERSION field results in an SQLCODE -138 error.
    An IDENTITY field can be made to accept user-specified values. By setting the SetIdentityInsert() method of the %SYSTEM.SQL class you can override the IDENTITY field default constraint and allow inserts of unique integer values to IDENTITY fields. (You can return the current setting for this constraint by calling the GetIdentityInsert() method.) Inserting an IDENTITY field value changes the IDENTITY counter so that subsequent system-generated values increment from this user-specified value. Attempting to insert a NULL for an IDENTITY field generates an SQLCODE -108 error.
    IDKey data has the following restriction. Because multiple IDKey fields in an index are delimited using the “||” (double vertical bar) characters, you cannot include this character string in IDKey field data.
  • An insert cannot include a field whose value violates foreign key referential integrity, unless the %NOCHECK keyword is specified, or the foreign key was defined with the NOCHECK keyword. Otherwise, attempting an insert that violates foreign key referential integrity results in an SQLCODE -121 error, with a %msg such as the following: <Table 'Sample.MyTable', Foreign Key Constraint 'MYTABLEFKey2', Field(s) FULLNAME failed referential integrity check>. For details on listing a table’s foreign key constraints and the naming of foreign key constraints, refer to Catalog Details: Constraints.
  • A field value cannot be a subquery. Attempting to specify a subquery as a field value results in an SQLCODE -144 error.

The INSERT Operation

This section describes the operational considerations when performing an INSERT:

Privileges

To insert one or more rows of data into a table, you must have either table-level privileges or column-level privileges for that table.

Table-level Privileges

You must have both INSERT and SELECT privileges for the table. Failing to have these privileges results in an SQLCODE -99 error (Privilege Violation). You can determine if the current user has these privileges by invoking the %CHECKPRIV command. You can determine if a specified user has these privileges by invoking the $SYSTEM.SQL.CheckPriv() method. For privilege assignment, refer to the GRANT command.
To insert to a sharded table you must have INSERT privileges for the target table(s). Failing to have these privileges results in an SQLCODE -253 error: Sharded INSERT/UPDATE/DELETE run-time error.
Table-level privileges are equivalent to (but not identical to) having column-level privileges on all columns of the table.

Column-level Privileges

If you do not have table-level INSERT privilege, you must have column-level INSERT privilege for at least one column of the table. To insert a specified value into a column, you must have column-level INSERT privilege for that column. Only those columns for which you have INSERT privilege receive the value specified in the INSERT command.
If you do not have column-level INSERT privilege for a specified column, InterSystems SQL inserts the column's default value (if defined), or NULL (if no default is defined). If you do not have INSERT privilege for a column that has no default and is defined as NOT NULL, InterSystems IRIS issues an SQLCODE -99 (Privilege Violation) error at Prepare time.
If the INSERT command specifies fields in a WHERE clause of a result set SELECT, you must have SELECT privilege for those fields if they are not data insert fields, and both SELECT and INSERT privileges for those fields if they are included in the result set.
When a property is defined as ReadOnly, the corresponding table field is also defined as ReadOnly. A ReadOnly field may only be assigned a value using InitialExpression or SqlComputed. Attempting to insert a value for a field for which you have column-level ReadOnly (SELECT or REFERENCES) privilege results in an SQLCODE -138 error: Cannot INSERT/UPDATE a value for a read only field.
You can use %CHECKPRIV to determine if you have the appropriate column-level privileges. See the GRANT command for privilege assignment.

Fast Insert

When inserting rows in a table using JDBC, InterSystems IRIS by default automatically performs highly efficient Fast Insert operations. Fast Insert moves the normalization and formatting of the data being inserted from the server over to the client. The server can then directly set the whole row of data for a table into the global without manipulation on the server. This offloads these tasks from the server onto the client and can dramatically improve INSERT performance. Because the client is assuming the task of formatting the data, there may be an unforeseen usage increase in your client environment. You can use the FeatureOption property to disable Fast Insert if this is an issue.
Fast Insert must be supported on both the server and the client. To enabled or disabled Fast Insert in the client, use the FeatureOption property in the definition of the class instance as follows:
Properties p = new Properties();
p.setProperty("FeatureOption","3");   / 2 is fast Insert, 1 is fast Select, 3 is both
If Fast Insert is active, an INSERT executed using a cached query is performed using Fast Insert. This initial INSERT that generated the cached query is not performed using Fast Insert. This enables you to compare the performance of the initial insert with subsequent Fast Inserts executed using the cached query. If Fast Insert is not supported (for any of the following reasons), an ordinary INSERT is performed.
Fast Insert must be performed on a table. It cannot be performed on an updateable view. Fast Insert is not performed when the table has any of the following characteristics:
Fast Insert cannot be performed if the INSERT statement has any of the following characteristics:
For SQL xDBC Statement auditing events, an INSERT statement that uses the Fast Insert interface has a description of SQL fastINSERT Statement. If the Fast Insert interface is used, the Audit event does not include any parameter data, but includes the message Parameter values are not available for a fastInsert statement.

Referential Integrity

If you do not specify the %NOCHECK keyword, InterSystems IRIS uses the system configuration setting to determine whether to perform foreign key referential integrity checking. You can set this system default using the $SYSTEM.SQL.SetFilerRefIntegrity() method call. To determine the current setting, call $SYSTEM.SQL.CurrentSettings(). The default is “Yes”. If you change this setting, any new process started after changing it will have the new setting.
This setting does not apply to foreign keys that have been defined with the NOCHECK keyword.
During an INSERT operation, for every foreign key reference a shared lock is acquired on the corresponding row in the referenced table. This row is locked while performing referential integrity checking and inserting the row. The lock is then released (it is not held until the end of the transaction). This ensures that the referenced row is not changed between the referential integrity check and the completion of the insert operation.
However, if you specify the %NOLOCK keyword, no locking is performed either on the specified table or on the corresponding foreign key row in the referenced table.

Child Table Insert

During an INSERT operation on a child table, a shared lock is acquired on the corresponding row in the parent table. This row is locked while inserting the child table row. The lock is then released (it is not held until the end of the transaction). This ensures that the referenced parent row is not changed during the insert operation.

Atomicity

By default, INSERT, UPDATE, DELETE, and TRUNCATE TABLE are atomic operations. An INSERT either completes successfully or the whole operation is rolled back. If any of the specified rows cannot be inserted, none of the specified rows are inserted and the database reverts to its state before issuing the INSERT.
You can modify this default for the current process within SQL by invoking SET TRANSACTION %COMMITMODE. You can modify this default for the current process in ObjectScript by invoking the SetAutoCommit() method. The following options are available:
  • IMPLICIT or 1 (autocommit on) — The default behavior, as described above. Each INSERT constitutes a separate transaction.
  • EXPLICIT or 2 (autocommit off) — If no transaction is in progress, an INSERT automatically initiates a transaction, but you must explicitly COMMIT or ROLLBACK to end the transaction. In EXPLICIT mode the number of database operations per transaction is user-defined.
  • NONE or 0 (no auto transaction) — No transaction is initiated when you invoke INSERT. A failed INSERT operation can leave the database in an inconsistent state, with some of the specified rows inserted and some not inserted. To provide transaction support in this mode you must use START TRANSACTION to initiate the transaction and COMMIT or ROLLBACK to end the transaction.
    A sharded table is always in no auto transaction mode, which means all inserts, updates, and deletes to sharded tables are performed outside the scope of a transaction.
You can determine the atomicity setting for the current process using the GetAutoCommit() method, as shown in the following ObjectScript example:
  DO $SYSTEM.SQL.SetAutoCommit($RANDOM(3))
  SET x=$SYSTEM.SQL.GetAutoCommit()
  IF x=1 {
    WRITE "Default atomicity behavior",!
    WRITE "automatic commit or rollback" }
  ELSEIF x=0 {
    WRITE "No transaction initiated, no atomicity:",!
    WRITE "failed DELETE can leave database inconsistent",!
    WRITE "rollback is not supported" }
  ELSE { WRITE "Explicit commit or rollback required" }

Transaction Locking

If you do not specify the %NOLOCK keyword, the system automatically performs standard record locking on INSERT, UPDATE, and DELETE operations. Each affected record (row) is locked for the duration of the current transaction.
The default lock threshold is 1000 locks per table. This means that if you insert more than 1000 records from a table during a transaction, the lock threshold is reached and InterSystems IRIS automatically escalates the locking level from record locks to a table lock. This permits large-scale inserts during a transaction without overflowing the lock table.
InterSystems IRIS applies one of the two following lock escalation strategies:
  • “E”-type lock escalation: InterSystems IRIS uses this type of lock escalation if the following are true: (1) the class uses %Storage.Persistent (you can determine this from the Catalog Details in the Management Portal SQL schema display). (2) the class either does not specify an IDKey index, or specifies a single-property IDKey index. “E”-type lock escalation is described in the LOCK command in the ObjectScript Reference.
  • Traditional SQL lock escalation: The most likely reason why a class would not use “E”-type lock escalation is the presence of a multi-property IDKey index. In this case, each %Save increments the lock counter. This means if you do 1001 saves of a single object within a transaction, InterSystems IRIS will attempt to escalate the lock.
For both lock escalation strategies, you can determine the current systemwide lock threshold value using the $SYSTEM.SQL.GetLockThreshold() method. The default is 1000. This systemwide lock threshold value is configurable:
  • Using the Management Portal, select System Administration, Configuration, SQL and Object Settings, SQL. Display and edit the current setting of Lock escalation threshold. The default is 1000 locks. If you change this setting, any new process started after changing it will have the new setting.
You must have USE permission on the %Admin Manage Resource to change the lock threshold. InterSystems IRIS immediately applies any change made to the lock threshold value to all current processes.
On potential consequence of automatic lock escalation is a deadlock situation that might occur when an attempt to escalate to a table lock conflicts with another process holding a record lock in that table. There are several possible strategies to avoid this: (1) increase the lock escalation threshold so that lock escalation is unlikely to occur within a transaction. (2) substantially lower the lock escalation threshold so that lock escalation occurs almost immediately, thus decreasing the opportunity for other processes to lock a record in the same table. (3) apply a table lock for the duration of the transaction and do not perform record locks. This can be done at the start of the transaction by specifying LOCK TABLE, then UNLOCK TABLE (without the IMMEDIATE keyword, so that the table lock persists until the end of the transaction), then perform inserts with the %NOLOCK option.
Automatic lock escalation is intended to prevent overflow of the lock table. However, if you perform such a large number of inserts that a <LOCKTABLEFULL> error occurs, INSERT issues an SQLCODE -110 error.
For further details on transaction locking refer to Transaction Processing in the “Modifying the Database” chapter of Using InterSystems SQL.

Row-Level Security

InterSystems IRIS row-level security permits INSERT to add a row even if the row security is defined so that you will not be permitted to subsequently access the row. To ensure that an INSERT does not prevent you from subsequent SELECT access to the row, it is recommended that you perform the INSERT through a view that has a WITH CHECK OPTION. For further details, refer to CREATE VIEW.

Microsoft Access

To use INSERT to add data to an InterSystems IRIS table using Microsoft Access, either mark the table RowID field as private or define a unique index on one or more additional fields.

Embedded SQL and Dynamic SQL Examples

The following Embedded SQL example creates a new table SQLUser.MyKids. The examples that follow use INSERT to populate this table with data. After the INSERT examples, an example is provided to delete SQLUser.MyKids.
CreateTable
   &sql(CREATE TABLE SQLUser.MyKids (
    KidName VARCHAR(16) UNIQUE NOT NULL,
    KidDOB INTEGER NOT NULL,
    KidPetName VARCHAR(16) DEFAULT 'no pet') )
  IF SQLCODE=0 {
    WRITE !,"Table created" }
  ELSEIF SQLCODE=-201 {WRITE !,"Table already exists"  QUIT}
  ELSE {
    WRITE !,"CREATE TABLE failed. SQLCODE=",SQLCODE }
The following Embedded SQL example inserts a row with two field values (the third field, KidPetName, takes a default value). Note that the table schema name is supplied as a schema search path by the #SQLCompile Path macro directive:
EmbeddedSQLInsertByColName
  #SQLCompile Path=Sample
  NEW SQLCODE,%ROWCOUNT,%ROWID
  &sql(INSERT INTO MyKids (KidName,KidDOB) VALUES 
   ('Molly',60000))
  IF SQLCODE=0 {
    WRITE !,"Insert succeeded"
    WRITE !,"Row count=",%ROWCOUNT
    WRITE !,"Row ID=",%ROWID
    QUIT }
  ELSEIF SQLCODE=-119 {
    WRITE !,"Duplicate record not written",!
    WRITE %msg,!
    QUIT }
  ELSE {
    WRITE !,"Insert failed, SQLCODE=",SQLCODE }
The following Embedded SQL example inserts a row with three field values using the table's column order:
EmbeddedSQLInsertByColOrder
  NEW SQLCODE,%ROWCOUNT,%ROWID
  &sql(INSERT INTO SQLUser.MyKids VALUES ('Josie','40100','Fido') )
  IF SQLCODE=0 {
    WRITE !,"Insert succeeded"
    WRITE !,"Row count=",%ROWCOUNT
    WRITE !,"Row ID=",%ROWID
    QUIT }
  ELSEIF SQLCODE=-119 {
    WRITE !,"Duplicate record not written",!
    WRITE %msg,!
    QUIT }
  ELSE {
    WRITE !,"Insert failed, SQLCODE=",SQLCODE }
The following Embedded SQL example uses host variables to insert a row with two field values. The INSERT syntax used here specifies column=value pairs:
EmbeddedSQLInsertHostVars
  #SQLCompile Path=Sample
  NEW SQLCODE,%ROWCOUNT,%ROWID
  SET x = "Sam"
  SET y = "57555"
  &sql(INSERT INTO MyKids SET KidName=:x,KidDOB=:y )
  IF SQLCODE=0 {
    WRITE !,"Insert succeeded"
    WRITE !,"Row count=",%ROWCOUNT
    WRITE !,"Row ID=",%ROWID
    QUIT }
  ELSEIF SQLCODE=-119 {
    WRITE !,"Duplicate record not written",!
    WRITE %msg,!
    QUIT }
  ELSE {
    WRITE !,"Insert failed, SQLCODE=",SQLCODE }
The following Embedded SQL example uses a host variable array to insert a row with three field values. Array elements are numbered in column order. Note that user-supplied array values start with myarray(2); the first array element corresponds to the RowID column, which is automatically supplied and cannot be user-defined:
EmbeddedSQLInsertHostVarArray
  #SQLCompile Path=Sample
  NEW SQLCODE,%ROWCOUNT,%ROWID
  SET myarray(2)="Deborah"
  SET myarray(3)=60200
  SET myarray(4)="Bowie"
  &sql(INSERT INTO MyKids VALUES :myarray())
  IF SQLCODE=0 {
    WRITE !,"Insert succeeded"
    WRITE !,"Row count=",%ROWCOUNT
    WRITE !,"Row ID=",%ROWID
    QUIT }
  ELSEIF SQLCODE=-119 {
    WRITE !,"Duplicate record not written",!
    WRITE %msg,!
    QUIT }
  ELSE {
    WRITE !,"Insert failed, SQLCODE=",SQLCODE }
The following Dynamic SQL example uses the %SQL.Statement class to insert a row with three field values. Note that the table schema name is supplied as a schema search path in the %New() method:
COSDynamicSQLInsert
  SET x = "Noah"
  SET y = "61000"
  SET z = "Luna"
  SET sqltext = "INSERT INTO MyKids (KidName,KidDOB,KidPetName) VALUES (?,?,?)"
  SET tStatement = ##class(%SQL.Statement).%New(0,"Sample")
  SET qStatus = tStatement.%Prepare(sqltext)
    IF qStatus'=1 {WRITE "%Prepare failed:" DO $System.Status.DisplayError(qStatus) QUIT}
  SET rtn = tStatement.%Execute(x,y,z)
  IF rtn.%SQLCODE=0 {
    WRITE !,"Insert succeeded"
    WRITE !,"Row count=",rtn.%ROWCOUNT
    WRITE !,"Row ID=",rtn.%ROWID }
  ELSEIF rtn.%SQLCODE=-119 {
    WRITE !,"Duplicate record not written",!,rtn.%Message
    QUIT }
  ELSE {
    WRITE !,"Insert failed, SQLCODE=",rtn.%SQLCODE }
For further details, refer to the Embedded SQL and Dynamic SQL chapters in Using InterSystems SQL.
The following Embedded SQL example displays the inserted records, then deletes the SQLUser.MyKids table:
DisplayAndDeleteTable
  SET myquery = "SELECT * FROM SQLUser.MyKids"
  SET tStatement = ##class(%SQL.Statement).%New()
  SET qStatus = tStatement.%Prepare(myquery)
    IF qStatus'=1 {WRITE "%Prepare failed:" DO $System.Status.DisplayError(qStatus) QUIT}
  SET rset = tStatement.%Execute()
  DO rset.%Display()
  WRITE !,"End of data"
  &sql(DROP TABLE SQLUser.MyKids)
   IF SQLCODE=0 {
    WRITE !,"Deleted table"
    QUIT }
  ELSE {
    WRITE !,"Table delete failed, SQLCODE=",SQLCODE }
The following Embedded SQL example demonstrates the use of a host variable arrays. Note that with a host variable array, you can use a dynamic local array with an unspecified last subscript to pass an array of values to INSERT at runtime. For example:
  NEW SQLCODE,%ROWCOUNT,%ROWID
  &sql(INSERT INTO Sample.Employee VALUES :emp('profile',))
  WRITE !,"SQL Error code: ",SQLCODE," Row Count: ",%ROWCOUNT
causes each field in the inserted "Employee" row to be set to:
emp("profile",col)
where "col" is the field’s column number in the Sample.Employee table.
The following example shows how the results of a SELECT query can be used as the data input into an INSERT statement, supplying the data for multiple rows:
INSERT INTO StudentRoster (NAME,GPA,ID_NUM)
     SELECT FullName,GradeAvg,ID
     FROM temp WHERE SchoolYear = '2004'

See Also

Previous section   Next section