Skip to content

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 ​

PinKindTypesDescription
Inputinputgenerated <flow namespace>.<TypePrefix><Table>TableThe row to write.
Continuecontinue outputsame as input (the table type)Called with the (updated) input record after an insert or update.

Configuration ​

FieldTypeDefaultDescription
ConnectionStringdatabase link nameRequired. Name of a repository database link (link selector). Looked up by exact name; a raw connection string or #name prefix is not resolved.
TypePrefixstringDbPrefix of the generated type name.
TableNamestring (database explorer)Required. table or schema.table; without a schema the link's default schema is used. Triggers reconfigure.
WriteOperationdropdown: 1 Insert, 2 Update, 3 Upsert, 4 Delete1Operation per record.
CommandTimeOutinteger (seconds)20Command timeout.
KeepOriginalNamesbooleanfalsetrue 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 named TypePrefix + table name + Table (suffix omitted if the name already ends with Table; converted to a C# name unless KeepOriginalNames). It becomes the only type of Input and Continue. A component with its default name is renamed to TWD_<TableName>. Changing TypePrefix or KeepOriginalNames alone 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 WHERE clause; on ClickHouse by the sorting / primary / partition key.
  • Operations:
    • 1 Insert: inserts the row; generated values (identity, primary key, computed columns) are read back in the same statement and written into the input record: SQL Server OUTPUT (through a temporary table when the table has enabled triggers), PostgreSQL RETURNING, Oracle RETURNING ... INTO, Db2 FINAL TABLE, MySQL/MariaDB a SELECT by LAST_INSERT_ID() in the same command (only with an auto increment column). Then Continue.
    • 2 Update: updates by primary key, then Continue (also when no row matched).
    • 3 Upsert: 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. Then Continue. 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.
    • 4 Delete: deletes by primary key. Continue is not called.

Notes ​

  • The input type is taken from the first Input connection 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 setting enable_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

Viaducta documentation