Expressions¶
This page covers the more advanced expression types: arithmetic, string concatenation, CASE, CAST, scalar functions, stored procedure calls, and batches.
Arithmetic expressions¶
Siqqle supports all standard arithmetic operators via SqlExpression factory methods:
| Method | SQL operator |
|---|---|
SqlExpression.Add(left, right) |
+ |
SqlExpression.Subtract(left, right) |
- |
SqlExpression.Multiply(left, right) |
* |
SqlExpression.Divide(left, right) |
/ |
SqlExpression.Modulo(left, right) |
% |
Both operands can be columns, constants, parameters, or other expressions.
Computed column¶
var sql = Sql
.Select(
(SqlColumn)"Name",
SqlExpression.Multiply((SqlColumn)"Quantity", (SqlColumn)"UnitPrice")
)
.From("OrderItems")
.ToSql();
Arithmetic with constants¶
var sql = Sql
.Select(
(SqlColumn)"Name",
SqlExpression.Add((SqlColumn)"Price", (SqlConstant)10)
)
.From("Products")
.ToSql();
Nested arithmetic¶
Chain operations to build complex formulas:
// (Price * Quantity) - Discount
var total = SqlExpression.Subtract(
SqlExpression.Multiply((SqlColumn)"Price", (SqlColumn)"Quantity"),
(SqlColumn)"Discount"
);
var sql = Sql
.Select((SqlColumn)"OrderId", total)
.From("OrderLines")
.ToSql();
Arithmetic in WHERE¶
var sql = Sql
.Select("Id", "Name")
.From("Products")
.Where(SqlExpression.GreaterThan(
SqlExpression.Multiply((SqlColumn)"Price", (SqlColumn)"Quantity"),
(SqlConstant)1000
))
.ToSql();
Arithmetic in UPDATE¶
Increment a column value:
var sql = Sql
.Update("Products")
.Set("Stock", SqlExpression.Subtract((SqlColumn)"Stock", (SqlConstant)1))
.Where(SqlExpression.Equal("Id", 5))
.ToSql();
String concatenation¶
Use SqlExpression.Concat() to concatenate two values. The SQL output depends on the dialect:
| Dialect | Concatenation syntax |
|---|---|
| Default / PostgreSQL | left \|\| right |
| SQL Server | left + right |
| MySQL | CONCAT(left, right) |
var sql = Sql
.Select(SqlExpression.Concat((SqlColumn)"FirstName", (SqlColumn)"LastName"))
.From("Users")
.ToSql();
Chain Concat calls to join multiple values:
var fullName = SqlExpression.Concat(
SqlExpression.Concat((SqlColumn)"FirstName", (SqlConstant)" "),
(SqlColumn)"LastName"
);
var sql = Sql.Select(fullName).From("Users").ToSql();
CASE WHEN¶
Use SqlExpression.Case() to build a searched CASE expression. Chain .When().Then() pairs and close with .Else().End(alias):
var sql = Sql
.Select(
(SqlColumn)"Id",
(SqlColumn)"Name",
SqlExpression
.Case()
.When(SqlExpression.GreaterThan("Age", 60)).Then("Elder")
.When(SqlExpression.GreaterThan("Age", 18)).Then("Adult")
.Else("Child")
.End("AgeGroup")
)
.From("User")
.ToSql();
SELECT [Id], [Name],
CASE WHEN [Age] > 60 THEN 'Elder'
WHEN [Age] > 18 THEN 'Adult'
ELSE 'Child'
END AS [AgeGroup]
FROM [User]
CASE without ELSE¶
The .Else() clause is optional — omit it and the CASE returns NULL when no condition matches:
var sql = Sql
.Select(
(SqlColumn)"Id",
SqlExpression
.Case()
.When(SqlExpression.Equal("Status", "Active")).Then("Yes")
.End("IsActive")
)
.From("Users")
.ToSql();
CASE without alias¶
If you don't need an alias, call .End() with no arguments:
SqlExpression
.Case()
.When(SqlExpression.GreaterThan("Score", 90)).Then("A")
.When(SqlExpression.GreaterThan("Score", 80)).Then("B")
.Else("C")
.End()
CASE value WHEN¶
The Case(value) overload generates a simple (value-based) CASE:
var sql = Sql
.Select(
(SqlColumn)"Id",
(SqlColumn)"Name",
SqlExpression
.Case((SqlColumn)"Age")
.When(30).Then("Thirty")
.When(20).Then("Twenty")
.Else((SqlColumn)"Age")
.End("AgeString")
)
.From("User")
.ToSql();
SELECT [Id], [Name],
CASE [Age] WHEN 30 THEN 'Thirty'
WHEN 20 THEN 'Twenty'
ELSE [Age]
END AS [AgeString]
FROM [User]
CAST¶
Convert a value to a different data type with SqlExpression.Cast():
var sql = Sql
.Select(
(SqlColumn)"Id",
(SqlColumn)"Name",
SqlExpression.Cast((SqlColumn)"Age", SqlDataType.Float(10))
)
.From("User")
.ToSql();
Available data types¶
SqlDataType exposes static factory methods for every common SQL type:
| Method | SQL type |
|---|---|
SqlDataType.Bit() |
BIT |
SqlDataType.TinyInt() |
TINYINT |
SqlDataType.SmallInt() |
SMALLINT |
SqlDataType.Int() |
INT |
SqlDataType.BigInt() |
BIGINT |
SqlDataType.Float(precision) |
FLOAT(n) |
SqlDataType.Real() |
REAL |
SqlDataType.Decimal(precision, scale) |
DECIMAL(p, s) |
SqlDataType.Char(size) |
CHAR(n) |
SqlDataType.VarChar(size) |
VARCHAR(n) |
SqlDataType.NChar(size) |
NCHAR(n) |
SqlDataType.NVarChar(size) |
NVARCHAR(n) |
SqlDataType.Binary(size) |
BINARY(n) |
SqlDataType.VarBinary(size) |
VARBINARY(n) |
SqlDataType.Date() |
DATE |
SqlDataType.Time() |
TIME |
SqlDataType.DateTime() |
DATETIME |
SqlDataType.DateTime2() |
DATETIME2 |
SqlDataType.UniqueIdentifier() |
UNIQUEIDENTIFIER |
CAST examples¶
// Cast to VARCHAR(100)
SqlExpression.Cast((SqlColumn)"Name", SqlDataType.VarChar(100))
// Cast to DECIMAL(10, 2)
SqlExpression.Cast((SqlColumn)"Price", SqlDataType.Decimal(10, 2))
// Cast to INT
SqlExpression.Cast((SqlColumn)"StringValue", SqlDataType.Int())
Scalar functions¶
Use SqlFunction to call any SQL function by name:
Pass arguments and an optional alias:
var sql = Sql
.Select(new SqlFunction("COALESCE", [(SqlColumn)"Name", (SqlColumn)"Email"], "DisplayName"))
.From("Users")
.ToSql();
Built-in helpers: LOWER / UPPER¶
var sql = Sql
.Select(
SqlFunction.Lower((SqlColumn)"Email"),
SqlFunction.Upper((SqlColumn)"Name")
)
.From("Users")
.ToSql();
Functions can be nested:
var sql = Sql
.Select(SqlFunction.Upper(SqlFunction.Lower((SqlColumn)"Name")))
.From("Users")
.ToSql();
Custom function with multiple arguments¶
var sql = Sql
.Select(new SqlFunction("ISNULL", [(SqlColumn)"MiddleName", (SqlConstant)"N/A"], "MiddleName"))
.From("Users")
.ToSql();
Stored procedures¶
Use Sql.Call() to generate a stored procedure invocation. The SQL produced depends on the dialect.
Stored procedure with multiple arguments¶
var sql = Sql
.Call(
"sp_SearchUsers",
"Name" + (SqlConstant)"John",
"MinAge" + (SqlConstant)18,
"MaxAge" + (SqlConstant)65
)
.ToSql(new SqlServerDialect());
Batching statements¶
Sql.Batch() concatenates multiple statements, separating them with a statement delimiter (;):
var sql = Sql.Batch(
Sql.Insert().Into("Log", "Message").Values("Started"),
Sql.Update("Job").Set("Status", "Running").Where(SqlExpression.Equal("Id", 1)),
Sql.Insert().Into("Log", "Message").Values("Done")
).ToSql();
INSERT INTO [Log] ([Message]) VALUES ('Started');
UPDATE [Job] SET [Status] = 'Running' WHERE [Id] = 1;
INSERT INTO [Log] ([Message]) VALUES ('Done')
Batches accept any SqlStatement types — you can mix INSERT, UPDATE, DELETE, and SELECT statements:
var sql = Sql.Batch(
Sql.Delete().From("TempData"),
Sql.Insert().Into("TempData", "Value").Values("Refreshed"),
Sql.Select("Value").From("TempData")
).ToSql();
DELETE FROM [TempData];
INSERT INTO [TempData] ([Value]) VALUES ('Refreshed');
SELECT [Value] FROM [TempData]
Sql.Batch() also accepts ISqlSyntaxEnd<SqlStatement> parameters, so you can pass fluent builder results directly without calling .Go().
Batches with Dapper¶
Use QueryMultiple to process multiple result sets from a batch:
using var multi = connection.QueryMultiple(
Sql.Batch(
Sql.Select("Id", "Name").From("Users"),
Sql.Select("Id", "Title").From("Posts")
)
);
var users = multi.Read<User>();
var posts = multi.Read<Post>();
See Dapper Integration for more details. ```