Skip to content

Transaction Groups ​

Last updated

License feature: Transaction Groups

A transaction group writes a snapshot of several tag values as one row — in a local Data Table or in a table on a remote SQL Server, MySQL, PostgreSQL, Oracle or ODBC database — every hour, every time a part counter changes, when a machine raises a "part done" bit, when a condition becomes true, or when a schedule says so. It can then write a handshake tag so the machine knows the row was stored. Use it for production logs, shift snapshots and batch records.

Where and who ​

Visualize → Data Infrastructure, tab Transaction Groups. Needs the transaction_groups licensed feature. Viewing needs any role; creating, editing and Execute now need editor; deleting needs admin.

What happens on each run ​

  1. Scada.Ink reads the cached value of every mapped tag (it does not poll the device).
  2. It converts each value to the column's type: Real (decimal), Integer or Text. A value that is not a number becomes empty (NULL); a tag with no value yet becomes NULL.
  3. It inserts one row into the target table with those columns.
    • Local data table: the table's built-in created_at records when the row was added (UTC). If the table also has a column named timestamp, that is filled with the time in ISO 8601 UTC (2026-09-15T14:00:00.012Z).
    • Remote database: if Timestamp column is set, that column is filled with the time the group ran.
  4. It writes the On success or On failure handshake tag, if set (see Handshake below).

Values are read the moment the trigger fires, before anything is sent to the database. It always inserts; it never updates existing rows.

Prepare the target table ​

For a local target, create a Data Table with a column for every mapping.

  1. In Data Tables, create a table named Hourly Press Log.
  2. Add columns die_temp (Real), part_count (Integer), job (Text).

Create a group ​

  1. Open Data Infrastructure → Transaction Groups and click New Transaction Group.
  2. Name: Hourly press snapshot.
  3. Write to: Local data table. Target Table: pick Hourly Press Log from the list.
  4. Trigger Type: Timer (interval), Interval (seconds) 3600.
  5. Under Column Mapping (tag → table column) click Add Column for each value: pick Column name die_temp, enter Device ID 3 and Tag path HR100, type Real; and so on.
  6. Leave Enabled — runs on its trigger ticked, or untick it to test first. Click Create.
  7. Click Execute now (the play icon). A message under the list says the row was written, or why it couldn't be.

Fields ​

FieldWhat it doesDefaultNotes
NameLabel—Required
Write toLocal data table or Remote databaseLocal
Target TableLocal: a Data Table, picked from the list—Required; saving fails with Data table "…" does not exist if it's gone
ConnectionRemote: a saved remote database connection—It must have data table writes turned on under its write permissions; the list marks those that don't
TableRemote: the table's name on the server, optionally schema.table—Letters, digits, underscores ($/# allowed after the first character)
Timestamp column (optional)Remote: a column filled with the time the group ranblankLeave blank if the table fills its own
Trigger TypeTimer (interval), Tag Change, Rising edge or ConditionTimerSchedule-run groups show Schedule
Interval (seconds)Timer period600 or blank means 60
Trigger TagTag Change, Rising edge and Condition (compare): the device and tag to watch, picked from the lists—Required
ConditionTag compared with a value or ExpressionTag comparedSee Triggers
Comparison / ValueCompare mode: >, >=, <, <=, ==, != and the value>=Numbers compare as numbers, anything else as text
ExpressionExpression mode: an expression tag expression using {deviceId:tagPath} references—Must reference at least one tag
Column nameLocal: picked from the table's columns. Remote: typed—Local saving fails with has no column named … otherwise; remote names are checked when the group runs
Handshake: On success / On failureTick to write a tag after each run: device, tag, Value to writeoff; value 1 / 0See Handshake
Enabled — runs on its triggerWhether the trigger runs the grouponExecute now works either way
Device ID / Tag pathSource tag for this column—Local tags use the Local Tags device's id
TypeReal, Integer or TextRealUse Integer (0/1) or Text for booleans

The list shows each group with its trigger, target (a remote one as connection: table) and Last run, with "queued in store & forward (database unreachable)" or "failed: …" and the reason when the last run didn't write; a switch to turn the group on or off; and icons for Execute now, Edit and Delete. Delete asks first ("Delete transaction group?"); rows already written stay in their table.

Triggers ​

  • Timer (interval) runs every N seconds from the moment the group was loaded (API start or last save), not aligned to the clock. For rows exactly on the hour, use a schedule instead.
  • Tag Change runs on every change of the watched tag — each count of a part counter, each flicker of a bit, after the tag's deadband.
  • Rising edge runs once each time the tag goes from off to on: from 0, false or empty to a non-zero number or true. It doesn't run again while the tag stays on, only after it has gone off and on again. Use it for a PLC "part complete" or "batch done" bit.
  • Condition runs once each time a condition becomes true, and not again until it has been false. Tag compared with a value checks one tag (for example Tank/Level >= 80) on each change of that tag. Expression is re-checked whenever any tag it references changes, and counts as true when it gives a non-zero number or true, for example if({1:Line/Running} == 1 && {1:Line/Count} >= 100, 1, 0).
  • For Rising edge and Condition, the first value read after the group starts (saving any group, or an appliance restart) only sets the starting point: a trigger already on at that moment does not run the group.
  • Schedule: on the Schedules page create a schedule with the action Execute Transaction Group and a cron expression such as 0 * * * *. See Schedules.

Writing to a remote database ​

  1. Under Remote DBs, open the connection and turn on data table writes under its write permissions.
  2. Create the table on the server with the columns you'll map, plus one for the time if you want it, for example CREATE TABLE production_log (id INT IDENTITY PRIMARY KEY, logged_at DATETIME2, part_count INT, die_temp FLOAT).
  3. In the group, choose Write to → Remote database, the Connection, Table production_log and Timestamp column logged_at, then type each Column name.
  4. Click Execute now to prove the names: a wrong table or column shows the database's own error.

When a triggered run can't reach the database, the row is queued in store & forward and written when the connection is back; the list shows "queued in store & forward". Execute now writes directly instead, so a mistake shows at once rather than being queued. Table and column names are quoted with [ ] on SQL Server and backticks on MySQL; on PostgreSQL, Oracle and ODBC they are sent unquoted, so the database's usual case rules apply (PostgreSQL folds to lower case).

Handshake ​

A handshake tells the machine whether its data was stored, the way a PLC waits for an acknowledgement before it clears its buffer or moves on.

  • On success writes Value to write (default 1) to the chosen tag after the row is inserted. A row queued in store & forward also counts as success: it is stored on the appliance and will be delivered.
  • On failure writes its value (default 0) when the run fails.
  • The tag can be a local tag, a simulator tag or a tag on a real device; a real device must have writes enabled in its settings, as for scripts. A handshake that can't be written is logged as a warning and doesn't change the run's result.
  • Execute now writes the handshake too.

A common pattern: the PLC sets PartDone to 1, the group (Rising edge on PartDone) stores the row and writes 0 back to PartDone as its success handshake, ready for the next part.

Behavior to know ​

  • Turn a group off with its switch to pause it; its settings are kept.
  • Saving any group reloads all groups, which restarts every timer.
  • When a run fails (missing table, missing column, database error), a notification Transaction Group Failed is sent once, and Transaction Group Recovered when it works again. The list shows the last error next to Last run.
  • Execute now runs the group once, even when it is turned off, and shows whether the row was written or the error.
  • Rows accumulate; add a scheduled script or named query to delete old rows if the table must not grow forever.

API ​

MethodPathRolePurpose
GET/api/data-infra/transaction-groupsviewerList groups
GET/api/data-infra/transaction-groups/:idviewerOne group
POST/api/data-infra/transaction-groupseditorCreate. Local: targetTable may be the table's display name or internal name; it and every columnName are checked. Remote: targetType: "remote", targetConnectionId, targetTable, optional timestampColumn. Triggers: triggerType timer, tag_change, rising_edge, condition (triggerConfig: { mode: "compare", deviceId, tagPath, operator, value } or { mode: "expression", expression }). handshake: { success?: { deviceId, tagPath, value }, failure?: { … } }
PUT/api/data-infra/transaction-groups/:ideditorUpdate (same fields)
DELETE/api/data-infra/transaction-groups/:idadminDelete
POST/api/data-infra/transaction-groups/:id/executeeditorRun now; answers { table, columns, buffered }, or 400 with the reason

Each group also returns lastResult (success, failed or buffered) and lastError.

Troubleshooting ​

SymptomCauseFix
Data table "…" does not existThe table was deleted or renamedPick the table again in Target Table
has no column named …A Column name does not match the tableCorrect the mapping
Columns are emptyTag has no cached value, wrong Device ID/Tag path, or a non-numeric value in a Real/Integer columnCheck the tag in Tags; use Text
Far too many rowsTag Change on a tag that changes constantlyUse Rising edge, Condition, a timer or a schedule
Name and target table are requiredMissing fieldFill both
Remote connection "…" does not allow data table writesThe connection's data table writes are offTurn them on under the connection's write permissions in Remote DBs
"…" is not a valid table name / column nameSpaces, quotes or other characters in a remote nameUse letters, digits and underscores, or rename on the server
Rising edge never firesThe tag was already on when the group started, or never goes back to 0Make the PLC reset the bit, or write 0 as the success handshake
Last run shows "queued in store & forward"The remote database was unreachableRows are sent when it is back; see Store & Forward
A handshake tag doesn't changeWrites are not enabled on that device, or the tag isn't writableEnable writes in the device's settings; see the API log for the warning

See also ​

Scada.Ink Help Center