using System.Collections;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Globalization;
public static void Main()
var a = DateTime.Now.SetDay(22);
var builder = new SqlBuilder()
.AS("q0.TicketID", "sfdsfdsf")
._("q0.SystemName AS Area")
.CASE("1<2", "Yes", "No", "Awesome")
.FROM("dbo.reports_sm_ticket q0")
.LEFT_JOIN("dbo.reports_sm_procedure_element q1 ON q1.TicketID = q0.TicketID")
._("(q0.nonhfc = 1 OR q0.hfc = 1)")
._("q0.ResolutionDescr <> 'Maintenance cancelled'")
._("q0.MaintenanceType = 'SA'")
._("q0.DivisionJoinID = 1");
Console.WriteLine(builder);
public partial class SqlBuilder
public SqlBuilder DISTINCT()
SetNextClause("SELECT DISTINCT", " ");
AppendClause("SELECT DISTINCT", "", "");
public StringBuilder Buffer { get; } = new StringBuilder();
public Collection<object> ParameterValues { get; } = new Collection<object>();
public string CurrentClause { get; set; }
public string CurrentSeparator { get; set; }
public string NextClause { get; set; }
public string NextSeparator { get; set; }
public bool IsEmpty => Buffer.Length == 0;
public SqlBuilder CASE(string condition, string @true, string @false, string name, params object[] args)
CASE(condition, @true, @false, args);
public static SqlBuilder JoinSql(string separator, params SqlBuilder[] values)
throw new ArgumentNullException(nameof(values));
var sql = new SqlBuilder();
SqlBuilder first = values[0];
for(int i = 1; i < values.Length; i++)
SqlBuilder val = values[i];
public SqlBuilder CASE(string condition, string trueValue, params object[] args)
if(CurrentClause != "CASE")
SetNextClause("CASE", " ");
AppendClause("CASE", " ", "WHEN");
AppendClause("CASE", " ", $"{condition}", args);
AppendClause("CASE", " THEN ", $"'{trueValue}'");
public SqlBuilder CASE(string condition, string trueValue, string falseValue, params object[] args)
CASE(condition, trueValue, args);
AppendClause("CASE", " ELSE ", $"'{falseValue}'");
public SqlBuilder CASE(string condition, int trueValue, params object[] args)
if(CurrentClause != "CASE")
SetNextClause("CASE", " ");
AppendClause("CASE", " ", "WHEN");
AppendClause("CASE", " ", $"{condition}", args);
AppendClause("CASE", " THEN ", trueValue.ToString());
public SqlBuilder CASE(string condition, int trueValue, int falseValue, params object[] args)
CASE(condition, trueValue, args);
AppendClause("CASE", " ELSE ", falseValue.ToString());
public SqlBuilder END(string name)
AppendClause("CASE", " END AS ", name);
CurrentClause = "SELECT";
public static SqlBuilder JoinSql(string separator, IEnumerable<SqlBuilder> values)
if(values == null) throw new ArgumentNullException(nameof(values));
var sql = new SqlBuilder();
using(IEnumerator<SqlBuilder> enumerator = values.GetEnumerator())
if(!enumerator.MoveNext())
if(enumerator.Current != null)
sql.Append(enumerator.Current);
while(enumerator.MoveNext())
if(enumerator.Current != null)
sql.Append(enumerator.Current);
public SqlBuilder(string format, params object[] args)
public SqlBuilder AppendClause(string clauseName, string separator, string format, params object[] args)
!string.Equals(clauseName, CurrentClause, StringComparison.OrdinalIgnoreCase))
Buffer.Append(clauseName);
else if(separator != null)
Buffer.Append(separator);
CurrentClause = clauseName;
CurrentSeparator = separator;
public SqlBuilder AppendToCurrentClause(string format, params object[] args)
var clause = CurrentClause;
var separator = CurrentSeparator;
separator = NextSeparator;
AppendClause(clause, separator, format, args);
public SqlBuilder Append(SqlBuilder sql)
Buffer.Append(MakeAbsolutePlaceholders(sql));
for(int i = 0; i < sql.ParameterValues.Count; i++)
ParameterValues.Add(sql.ParameterValues[i]);
public SqlBuilder Append(string format, params object[] args)
if(args == null || args.Length == 0)
var fargs = new List<string>();
for(int i = 0; i < args.Length; i++)
SqlList list = obj as SqlList;
fargs.Add(string.Join(", ", Enumerable.Range(0, list.Count).Select(x => Placeholder(ParameterValues.Count + x))));
for(int j = 0; j < list.Count; j++)
ParameterValues.Add(list[j]);
var sqlb = obj as SqlBuilder;
GetDefiningQueryFromObject(obj, ref sqlb);
var sqlfrag = new StringBuilder()
.Append(MakeAbsolutePlaceholders(sqlb))
.Replace(Environment.NewLine, Environment.NewLine + "\t");
fargs.Add(sqlfrag.ToString());
for(int j = 0; j < sqlb.ParameterValues.Count; j++)
ParameterValues.Add(sqlb.ParameterValues[j]);
fargs.Add(Placeholder(ParameterValues.Count));
ParameterValues.Add(obj);
format = string.Join(" ", Enumerable.Range(0, fargs.Count).Select(i => Placeholder(i)));
Buffer.AppendFormat(CultureInfo.InvariantCulture, format, fargs.Cast<object>().ToArray());
partial void GetDefiningQueryFromObject(object obj, ref SqlBuilder definingQuery);
string MakeAbsolutePlaceholders(SqlBuilder sql)
CultureInfo.InvariantCulture,
Enumerable.Range(0, sql.ParameterValues.Count)
.Select(x => Placeholder(ParameterValues.Count + x))
static string Placeholder(int index)
=> string.Concat("{", index.ToString(CultureInfo.InvariantCulture), "}");
public SqlBuilder AppendLine()
public SqlBuilder Insert(int index, string value)
Buffer.Insert(index, value);
public SqlBuilder SetCurrentClause(string clauseName, string separator)
CurrentClause = clauseName;
CurrentSeparator = separator;
public SqlBuilder SetNextClause(string clauseName, string separator)
NextSeparator = separator;
public override string ToString()
public SqlBuilder Clone()
var clone = new SqlBuilder();
clone.Buffer.Append(Buffer.ToString());
clone.CurrentClause = CurrentClause;
clone.CurrentSeparator = CurrentSeparator;
foreach(object item in ParameterValues)
clone.ParameterValues.Add(item);
public SqlBuilder _(string format, params object[] args)
=> AppendToCurrentClause(format, args);
public SqlBuilder _If(bool condition, string format, params object[] args)
=> condition ? _(format, args) : this;
public SqlBuilder _ForEach<T>(IEnumerable<T> items, string format, string itemFormat, string separator, Func<T, object[]> parametersFactory)
if(items == null) throw new ArgumentNullException(nameof(items));
if(itemFormat == null) throw new ArgumentNullException(nameof(itemFormat));
if(separator == null) throw new ArgumentNullException(nameof(separator));
string[] formatSplit = format.Split(new[] { "{0}" }, StringSplitOptions.None);
formatStart = formatSplit[0];
formatEnd = formatSplit[1];
if(parametersFactory == null)
parametersFactory = (item) => null;
var currentSeparator = NextSeparator ?? CurrentSeparator;
foreach(var item in items)
var tempate = itemFormat;
tempate = formatStart + tempate;
CurrentSeparator = separator;
AppendToCurrentClause(tempate, parametersFactory(item));
CurrentSeparator = currentSeparator;
public SqlBuilder _OR<T>(IEnumerable<T> items, string itemFormat, Func<T, object[]> parametersFactory)
=> _ForEach(items, "({0})", itemFormat, " OR ", parametersFactory);
public SqlBuilder WITH(string format, params object[] args)
=> AppendClause("WITH", null, format, args);
public SqlBuilder WITH(SqlBuilder subQuery, string alias)
=> WITH(alias + " AS ({0})", subQuery);
public SqlBuilder SELECT()
=> SetNextClause("SELECT", ", ");
public SqlBuilder SELECT(string format, params object[] args)
=> AppendClause("SELECT", ", ", format, args);
public SqlBuilder AS(string format, string name, params object[] args)
string.IsNullOrEmpty(name?.Trim()) ? format : $"{format} AS {name}",
public SqlBuilder SELECT_DISTINCT()
=> SetNextClause("SELECT DISTINCT", ", ");
public SqlBuilder FROM(string format, params object[] args)
=> AppendClause("FROM", ", ", format, args);
public SqlBuilder FROM(SqlBuilder subQuery, string alias)
=> FROM("({0}) " + alias, subQuery);
=> SetNextClause("JOIN", null);
public SqlBuilder JOIN(string format, params object[] args)
=> AppendClause("JOIN", null, format, args);
public SqlBuilder LEFT_JOIN(string format, params object[] args)
=> AppendClause("LEFT JOIN", null, format, args);
public SqlBuilder RIGHT_JOIN(string format, params object[] args)
=> AppendClause("RIGHT JOIN", null, format, args);
public SqlBuilder INNER_JOIN(string format, params object[] args)
=> AppendClause("INNER JOIN", null, format, args);
public SqlBuilder CROSS_JOIN(string format, params object[] args)
=> AppendClause("CROSS JOIN", null, format, args);
public SqlBuilder WHERE()
=> SetNextClause("WHERE", " AND ");
public SqlBuilder WHERE(string format, params object[] args)
=> AppendClause("WHERE", " AND ", format, args);
public SqlBuilder GROUP_BY()
=> SetNextClause("GROUP BY", ", ");
public SqlBuilder GROUP_BY(string format, params object[] args)
=> AppendClause("GROUP BY", ", ", format, args);
public SqlBuilder HAVING()
=> SetNextClause("HAVING", " AND ");
public SqlBuilder HAVING(string format, params object[] args)
=> AppendClause("HAVING", " AND ", format, args);
public SqlBuilder ORDER_BY()
=> SetNextClause("ORDER BY", ", ");
public SqlBuilder ORDER_BY(string format, params object[] args)
=> AppendClause("ORDER BY", ", ", format, args);
public SqlBuilder LIMIT()
=> SetNextClause("LIMIT", null);
public SqlBuilder LIMIT(string format, params object[] args)
=> AppendClause("LIMIT", null, format, args);
public SqlBuilder LIMIT(int maxRecords)
=> LIMIT("{0}", maxRecords);
public SqlBuilder OFFSET()
=> SetNextClause("OFFSET", null);
public SqlBuilder OFFSET(string format, params object[] args)
=> AppendClause("OFFSET", null, format, args);
public SqlBuilder OFFSET(int startIndex)
=> OFFSET("{0}", startIndex);
public SqlBuilder UNION()
=> AppendClause("UNION", null, null, null);
public SqlBuilder INSERT_INTO(string format, params object[] args)
=> AppendClause("INSERT INTO", null, format, args);
public SqlBuilder DELETE_FROM(string format, params object[] args)
=> AppendClause("DELETE FROM", null, format, args);
public SqlBuilder UPDATE(string format, params object[] args)
=> AppendClause("UPDATE", null, format, args);
public SqlBuilder SET(string format, params object[] args)
=> AppendClause("SET", ", ", format, args);
public SqlBuilder VALUES(params object[] args)
if(args == null || args.Length == 0)
throw new ArgumentException("args cannot be empty", nameof(args));
return AppendClause("VALUES", null, "({0})", SQL.List(args));
public static partial class SQL
public static object List(IEnumerable values) => new SqlList(values);
public static object List(params object[] values) => new SqlList(values);
public static SqlBuilder DELETE_FROM(string format, params object[] args) => new SqlBuilder().DELETE_FROM(format, args);
public static SqlBuilder INSERT_INTO(string format, params object[] args) => new SqlBuilder().INSERT_INTO(format, args);
public static SqlBuilder SELECT(string format, params object[] args) => new SqlBuilder().SELECT(format, args);
public static SqlBuilder UPDATE(string format, params object[] args) => new SqlBuilder().UPDATE(format, args);
public static SqlBuilder WITH(SqlBuilder subQuery, string alias) => new SqlBuilder().WITH(subQuery, alias);
public static SqlBuilder WITH(string format, params object[] args) => new SqlBuilder().WITH(format, args);
public static new bool Equals(object objectA, object objectB)
=> object.Equals(objectA, objectB);
public static new bool ReferenceEquals(object objectA, object objectB)
=> object.ReferenceEquals(objectA, objectB);
public object this[int index] => _values[index];
public int Count => _values.Length;
public SqlList(IEnumerable values)
var arr = values?.Cast<object>().ToArray();
if(arr == null || arr.Length == 0)
arr = new object[1] { null };