9.3 KiB
9.3 KiB
SqlBreakdownCollection Usage Guide
Overview
The SqlBreakdownCollection class provides a convenient way to manage multiple SQL breakdown objects and parse batch SQL statements. It offers LINQ support, StringBuilder-based optimization, and flexible parsing capabilities.
Basic Usage
Creating a Collection
// Create an empty collection
var collection = new SqlBreakdownCollection();
// Create with initial breakdowns
var breakdowns = new List<ISqlBreakdown> { breakdown1, breakdown2 };
var collection = new SqlBreakdownCollection(breakdowns);
Adding Breakdowns
var collection = new SqlBreakdownCollection();
// Add single breakdown
collection.Add(breakdown1);
// Add multiple breakdowns
collection.AddRange(new[] { breakdown2, breakdown3, breakdown4 });
Removing Items
// Remove a specific breakdown
collection.Remove(breakdown1);
// Clear all items
collection.Clear();
Batch Parsing
The ParseBatch method allows you to split a batch SQL statement into individual statements separated by GO keywords (or other separators).
Parsing with GO Separators
var collection = new SqlBreakdownCollection();
string batchSql = @"
SELECT * FROM Customers
GO
SELECT * FROM Orders WHERE Status = 'Pending'
GO
UPDATE Inventory SET Quantity = 0 WHERE ProductID = 123
";
collection.ParseBatch(batchSql);
// Access raw statements
foreach (var statement in collection.RawStatements)
{
Console.WriteLine(statement);
Console.WriteLine("---");
}
// Output:
// SELECT * FROM Customers
// ---
// SELECT * FROM Orders WHERE Status = 'Pending'
// ---
// UPDATE Inventory SET Quantity = 0 WHERE ProductID = 123
// ---
Handling GO Case-Insensitivity
The parser handles GO statements regardless of case:
string batchSql = @"
SELECT * FROM Table1
go
SELECT * FROM Table2
GO
SELECT * FROM Table3
Go
";
collection.ParseBatch(batchSql);
// Correctly parses into 3 statements
Handling Whitespace
GO statements with surrounding whitespace are correctly recognized:
string batchSql = @"
SELECT * FROM Table1
GO
SELECT * FROM Table2
GO
SELECT * FROM Table3
";
collection.ParseBatch(batchSql);
// Correctly parses into 3 statements
Combining SQL Statements
Getting Combined SQL from Breakdowns
var collection = new SqlBreakdownCollection(new[]
{
new QueryBreakdown { SelectClause = "col1, col2", FromClause = "table1" },
new QueryBreakdown { SelectClause = "col3, col4", FromClause = "table2" }
});
// Get combined SQL with GO separator (default)
string combinedSql = collection.GetCombinedSql();
// SELECT col1, col2 FROM table1
// GO
// SELECT col3, col4 FROM table2
// Get combined SQL with custom separator
string customSql = collection.GetCombinedSql(separator: ";");
// SELECT col1, col2 FROM table1
// ;
// SELECT col3, col4 FROM table2
// Get combined SQL without setup/finish clauses
string basicSql = collection.GetCombinedSql(includeSetupFinish: false);
Getting Batch SQL from Raw Statements
collection.ParseBatch(batchSql);
// Combine raw statements back into batch format
string reassembledBatch = collection.GetBatchSql();
// Use custom separator
string customBatch = collection.GetBatchSql(separator: ";");
LINQ Integration
Filtering with Where
var collection = new SqlBreakdownCollection(breakdowns);
// Find all SELECT queries
var selectQueries = collection.Where(b => b.ToString().Contains("SELECT"))
.ToList();
// Count queries
int queryCount = collection.Where(b => b.ToString().Contains("SELECT")).Count();
Projecting with Select
// Get SQL lengths
var queryLengths = collection.Select(b => b.ToString().Length).ToList();
// Get first 100 characters of each query
var summaries = collection.Select(b =>
b.ToString().Length > 100
? b.ToString().Substring(0, 100) + "..."
: b.ToString())
.ToList();
// Get query strings
var sqlStatements = collection.Select(b => b.GetSql()).ToList();
Finding Specific Items
// Get first breakdown matching criteria
var firstSelectQuery = collection.FirstOrDefault(b =>
b.ToString().Contains("SELECT"));
// Get by index
var secondBreakdown = collection.GetAt(1);
// Get raw statement by index
var secondStatement = collection.GetRawStatementAt(1);
Practical Examples
Example 1: Processing Multiple SQL Files
// Read multiple SQL files and combine
var collection = new SqlBreakdownCollection();
string[] sqlFiles = Directory.GetFiles(@"C:\sql-scripts", "*.sql");
foreach (var file in sqlFiles)
{
var content = File.ReadAllText(file);
collection.ParseBatch(content);
collection.AddRange(ParseBreakdowns(collection.RawStatements));
}
// Generate combined output
string output = collection.GetCombinedSql();
File.WriteAllText("combined_output.sql", output);
Example 2: Filtering and Processing Specific Queries
var collection = new SqlBreakdownCollection(allBreakdowns);
// Get all DELETE queries (with caution!)
var deleteQueries = collection.Where(b =>
b.ToString().ToUpper().Contains("DELETE"))
.ToList();
// Log them for review
foreach (var query in deleteQueries)
{
logger.Warn($"Potentially dangerous query: {query.GetSql()}");
}
// Get only safe SELECT queries
var safeQueries = collection.Where(b =>
!b.ToString().ToUpper().Contains("DELETE") &&
!b.ToString().ToUpper().Contains("DROP") &&
!b.ToString().ToUpper().Contains("TRUNCATE"))
.ToList();
// Execute safe queries
foreach (var query in safeQueries)
{
ExecuteQuery(query.GetSql());
}
Example 3: Batch Processing with Setup/Finish Clauses
// Create breakdowns with setup and finish clauses
var breakdown1 = new QueryBreakdown();
breakdown1.SelectClause.Clause = "* ";
breakdown1.FromClause.Clause = "Customers";
breakdown1.SetupClauses.Add("SET NOCOUNT ON;");
breakdown1.FinishClauses.Add("PRINT 'Customers query executed'");
var breakdown2 = new QueryBreakdown();
breakdown2.SelectClause.Clause = "*";
breakdown2.FromClause.Clause = "Orders";
breakdown2.FinishClauses.Add("PRINT 'Orders query executed'");
var collection = new SqlBreakdownCollection(new[] { breakdown1, breakdown2 });
// Generate SQL with all setup and finish clauses
string fullBatch = collection.GetCombinedSql(includeSetupFinish: true);
// Output includes all PRINT and NOCOUNT statements
Example 4: Analyzing Query Complexity
var collection = new SqlBreakdownCollection(allBreakdowns);
// Find complex queries
var complexQueries = collection
.Where(b =>
{
var sql = b.ToString();
return sql.Contains("JOIN") && sql.Contains("GROUP BY");
})
.Select(b => new
{
Statement = b.ToString(),
Length = b.ToString().Length
})
.OrderByDescending(x => x.Length)
.ToList();
foreach (var query in complexQueries)
{
Console.WriteLine($"Complex query ({query.Length} chars): {query.Statement}");
}
Collection Properties and Methods
| Member | Description |
|---|---|
Count |
Gets the number of breakdowns in the collection |
IsEmpty |
Gets whether the collection has no items |
Breakdowns |
Gets a read-only list of all breakdowns |
RawStatements |
Gets a read-only list of raw SQL statements |
Add(breakdown) |
Adds a single breakdown |
AddRange(breakdowns) |
Adds multiple breakdowns |
Remove(breakdown) |
Removes a breakdown |
Clear() |
Removes all items |
ParseBatch(sqlBatch) |
Parses batch SQL into statements |
GetCombinedSql() |
Gets formatted SQL from all breakdowns |
GetBatchSql() |
Gets batch format from raw statements |
Where(predicate) |
Filters breakdowns using LINQ |
Select<T>(selector) |
Projects breakdowns using LINQ |
GetAt(index) |
Gets breakdown at index |
FirstOrDefault(predicate) |
Gets first matching breakdown |
GetRawStatementAt(index) |
Gets raw statement at index |
ToString() |
Gets combined SQL string |
Performance Considerations
- StringBuilder Usage: The class uses
StringBuilderfor efficient string concatenation when combining multiple SQL statements - LINQ Compatibility: All LINQ operations are supported for maximum flexibility
- Lazy Evaluation: LINQ operations using
WhereandSelectsupport deferred execution - Memory Efficiency: Raw statements and breakdowns are stored separately to reduce duplication
Error Handling
The class includes robust error handling:
try
{
collection.Add(null); // Throws ArgumentNullException
}
catch (ArgumentNullException ex)
{
Console.WriteLine("Cannot add null breakdown");
}
try
{
collection.GetAt(100); // Throws IndexOutOfRangeException
}
catch (IndexOutOfRangeException ex)
{
Console.WriteLine("Index out of range");
}
try
{
collection.ParseBatch(null); // Throws ArgumentNullException
}
catch (ArgumentNullException ex)
{
Console.WriteLine("Batch cannot be null");
}
Related Classes
SqlBreakdownBase: Base class for all SQL breakdown implementationsQueryBreakdown: Represents SELECT queries with full clause supportInsertBreakdown: Represents INSERT statementsUpdateBreakdown: Represents UPDATE statementsDeleteBreakdown: Represents DELETE statementsISqlBreakdown: Interface for breakdown objects