SQL Task
SqlTask is a general-purpose task for executing raw SQL within ETLBox workflows. It supports direct SQL execution, scalar queries, reading result sets, and batch operations such as bulk insert, update, and delete. It’s especially useful when you need full control over the executed SQL while keeping the ADO.NET boilerplate out of your code.
Executing SQL Statements
Use ExecuteNonQuery
to run SQL statements that don’t return data (e.g., INSERT
, UPDATE
, DELETE
, TRUNCATE
):
SqlTask.ExecuteNonQuery("Insert rows", "INSERT INTO Orders (Amount) VALUES (100)");
Or with a connection manager:
var connectionManager = new SqlConnectionManager("connection string here");
SqlTask.ExecuteNonQuery(connectionManager, "DELETE FROM TempData");
With parameters:
var parameters = new List<QueryParameter> {
new QueryParameter("value1", "INT", 123),
new QueryParameter("value2", "NVARCHAR(50)", "Test")
};
SqlTask.ExecuteNonQuery(connectionManager,
"INSERT INTO Logs (Id, Message) VALUES (@value1, @value2)",
parameters);
Scalar Queries
Use ExecuteScalar
when the SQL returns a single value:
object result = SqlTask.ExecuteScalar(connectionManager, "SELECT COUNT(*) FROM Orders");
With type conversion:
int count = SqlTask.ExecuteScalar<int>(connectionManager, "SELECT COUNT(*) FROM Orders");
Reading Result Sets
SqlTask.ExecuteReader
allows you to process result sets row by row using delegate actions. This is useful when you want to map query results into objects or handle each row manually.
You provide a series of delegate actions:
- A function that initializes a new object before each row is read.
- An action that runs after each row is read (commonly used to add the object to a list).
- One or more actions to map column values to object properties.
Example usage:
List<Order> orders = new List<Order>();
Order current = null;
SqlTask.ExecuteReader(connectionManager,
"SELECT Id, Amount FROM Orders",
() => current = new Order(),
() => orders.Add(current),
col1 => current.Id = int.Parse(col1.ToString()),
col2 => current.Amount = decimal.Parse(col2.ToString())
);
You must provide exactly one mapper per column in the result set. If more mappers are provided than columns, an exception is thrown.
This pattern ensures clean object mapping without relying on reflection or dynamic typing. It’s also database-agnostic and works across all supported platforms.
Bulk Operations
BulkInsert
SqlTask.BulkInsert
allows you to insert multiple rows into a table efficiently using a TableData
object. It is optimized for performance and works across supported databases.
To use it, create a TableData
instance and populate it with rows matching the table’s schema:
var tableDef = new TableDefinition("Orders", new List<TableColumn> {
new TableColumn("Id", "INT"),
new TableColumn("Description", "VARCHAR(100)")
});
var data = new TableData<string[]>(tableDef);
data.Rows.Add(new[] { "1", "Test1" });
data.Rows.Add(new[] { "2", "Test2" });
SqlTask.BulkInsert(connectionManager, data);
You can also control how columns are mapped using the DataIndexForColumn
dictionary if your input arrays don’t match the column order:
data.DataIndexForColumn["Description"] = 0;
data.DataIndexForColumn["Id"] = 1;
Identity Handling
By default, identity columns are skipped during bulk insert. To insert explicit values into identity columns:
data.AllowIdentityInsert = true;
data.KeepIdentity = true;
This is useful in test scenarios or when importing data with preserved keys.
Column Converters
Use ColumnConverters
to transform input values before they are written:
data.ColumnConverters["CreatedDate"] = value =>
value == null ? DateTime.UtcNow : DateTime.Parse(value.ToString());
This allows for input normalization, parsing, or defaulting behavior at the column level.
BulkUpdate
SqlTask.BulkUpdate
lets you update multiple rows in a single operation by matching key columns and setting new values for specified fields. It uses a TableData
object to define both the data and the structure.
To perform a bulk update, define which columns should be used to match existing records (joinColumnNames
) and which columns should be updated (setColumnNames
):
var data = new TableData(tableDefinition);
data.Rows.Add(new object[] { 1, "UpdatedValue" }); // Example row
SqlTask.BulkUpdate(connectionManager, data,
setColumnNames: new[] { "Name" },
joinColumnNames: new[] { "Id" });
joinColumnNames
: Columns used to locate the target rows in the database.setColumnNames
: Columns whose values should be updated.
This method is efficient and works across most databases by generating a single batch update statement.
Handling Nulls
BulkUpdate
also handles NULL
values correctly. If a field in the input row is null
, it will be updated as NULL
in the database.
BulkDelete
SqlTask.BulkDelete
removes multiple rows from a table by matching each row’s values to specified columns in the database. Like the other bulk operations, it uses a TableData
object to define which records should be deleted.
Each row in TableData.Rows
is treated as a separate condition. The combination of all column values in a row is used to form a WHERE
clause that uniquely identifies records to delete.
Example:
var data = new TableData(new TableDefinition {
Name = "Orders",
Columns = new List<TableColumn> {
new TableColumn("Id"),
new TableColumn("Status")
}
});
data.Rows.Add(new object[] { 1, "Cancelled" });
data.Rows.Add(new object[] { 2, "Archived" });
SqlTask.BulkDelete(connectionManager, data);
This would result in a single DELETE
statement that removes any row in Orders
matching either (Id = 1 AND Status = 'Cancelled')
or (Id = 2 AND Status = 'Archived')
.
This approach is helpful for cleaning up test data, synchronizing subsets, or removing known duplicates.