Appearance
Table writer
Inserts, updates, upserts or deletes one row in a database table for every input record. The record type is generated from the table definition. After an insert, database-generated values (identity, primary key, computed columns) are written back into the record. Works inside a Sql transaction scope.
Pins
| Pin | Kind | Types | Description |
|---|---|---|---|
| Input | input | generated <flow namespace>.<TypePrefix><Table>Table | The row to write. |
| Continue | continue output | same as input (the table type) | Called with the (updated) input record after an insert or update. |
Configuration
| Field | Type | Default | Description |
|---|---|---|---|
ConnectionString | database link name | Required. Name of a repository database link (link selector). Looked up by exact name; a raw connection string or #name prefix is not resolved. | |
TypePrefix | string | Db | Prefix of the generated type name. |
TableName | string (database explorer) | Required. table or schema.table; without a schema the link's default schema is used. Triggers reconfigure. | |
WriteOperation | dropdown: 1 Insert, 2 Update, 3 Upsert, 4 Delete | 1 | Operation per record. |
CommandTimeOut | integer (seconds) | 20 | Command timeout. |
KeepOriginalNames | boolean | false | true keeps column names as property names (and the type name unconverted); false converts them to C# names. |
Behaviour
- Reconfigure (changing
TableName) reads the table definition and generates a locked type namedTypePrefix+ table name +Table(suffix omitted if the name already ends withTable; converted to a C# name unlessKeepOriginalNames). It becomes the only type ofInputandContinue. A component with its default name is renamed toTWD_<TableName>. ChangingTypePrefixorKeepOriginalNamesalone does not regenerate the type. - Every table column is bound from the input property with the same SQL column name; each statement sends only the columns it uses. Update and delete find the row by its primary key (and identity) columns in the
WHEREclause; on ClickHouse by the sorting / primary / partition key. - Operations:
1Insert: inserts the row; generated values (identity, primary key, computed columns) are read back in the same statement and written into the input record: SQL ServerOUTPUT(through a temporary table when the table has enabled triggers), PostgreSQLRETURNING, OracleRETURNING ... INTO, Db2FINAL TABLE, MySQL/MariaDB aSELECTbyLAST_INSERT_ID()in the same command (only with an auto increment column). ThenContinue.2Update: updates by primary key, thenContinue(also when no row matched).3Upsert: updates the row with the record's key, or inserts the record when there is none, in one atomic statement, and reads back generated values like insert. ThenContinue. Per database:- SQL Server:
MERGE ... WITH (HOLDLOCK). - PostgreSQL:
INSERT ... ON CONFLICT (primary key) DO UPDATE; when the key is an identity column, an update and an insert-if-not-updated in one statement (a new row gets a new id, so there is nothing to collide on). - MySQL/MariaDB:
INSERT ... ON DUPLICATE KEY UPDATE. The auto increment column is inserted too: a record with an id that isn't in the table is inserted with that id (NULL or 0 generates one). It also fires on other unique indexes, updating the row that matches there. - Oracle: a PL/SQL block: update, insert when no row was updated, update again if a concurrent writer inserted the key first.
- Snowflake:
MERGE(no generated values read back). - Db2: update, then insert when no row was updated, in two statements. Not atomic: two records with the same new key at the same time can both insert, which fails on the primary key. ClickHouse doesn't support upsert.
- SQL Server:
4Delete: deletes by primary key.Continueis not called.
Notes
- The input type is taken from the first
Inputconnection at start, and it must contain a property for every table column; otherwise the flow fails to start. Use the generated type (for example via a Data mapper). - Delete does not call
Continue; nothing after a delete-mode writer runs. - Update, upsert and delete need a primary key (or identity) column, and update/upsert at least one other writeable column; otherwise the flow fails to start.
- Snowflake and ClickHouse don't return generated values; the record keeps what it had.
- ClickHouse: update is a lightweight
UPDATE, which needs the table settingenable_block_number_column = 1(ALTER TABLE ... MODIFY SETTING enable_block_number_column = 1); on other tables it fails. Arrays can't be NULL: a null array property is written as an empty array. - One statement per record: for large volumes use Bulk insert.
Example
json
{ "ConnectionString": "MainDb", "TableName": "dbo.Customers", "WriteOperation": 3, "TypePrefix": "Db" }Json deserializer → Data mapper → Table writer → (Continue) Http response