我知道这可能是一个不好的例子,但在这种情况下我的问题更多地与处理StringBuilder而不是我的SQL查询本身的最好/最有效的方法有关,所以请耐心等待...... < / p>
作为一个示例来展示我想要实现的目标,假设我在数据库中有一个很大的表列表,所有表都具有相同的结构,我想创建一个查询在一个查询中从所有数据中提取数据。
我想这样做的方式是:
Dim MyTables As List(Of String) = {"Table1", "Table2", "Table3" ... "TableN"}.ToList
Dim SQLQuery As New StringBuilder
For Each tbl As String In MyTables
SQLQuery.AppendLine("SELECT [col1], [col2], [col3] FROM " & tbl)
SQLQuery.AppendLine("UNION")
Next
再一次,忽略这是否是最好的方法(虽然我很想知道是否有更好的方法,但我不希望答案在这个方向上倾斜 - 我更感兴趣在这种情况下知道如何有效地处理StringBuilder。)
鉴于我这样做的方式,我的StringBuilder将在其末尾有一个额外的UNION & vbCrLf
我需要删除 - 我知道我可以使用以下内容:
SQLQuery.Remove(SQLQuery.Length - ("UNION" & vbCrLf).Length, ("UNION" & vbCrLf).Length)
当然,我可以提高效率,但我的问题基本上是使用循环创建这样一个字符串构建器的最佳/最有效的方法是什么?“concatenator”就是这样的如果你按照我的方式做的那么会附加到末尾的相当大的字符串?
我知道这个问题是用VB编写的,但我同样对C#中的答案感到满意。致谢!!!
答案 0 :(得分:6)
当您需要构建一个由您选择的分隔符字符串分隔的集合元素组成的字符串时,您不需要直接使用StringBuilder
。此外,您甚至不需要循环:您可以使用带有分隔符和IEnumerable<T>
的{{3}}方法,并返回由您指定的任何分隔符分隔的集合元素组成的字符串:
// C# answer
var query = string.Join(
"\nUNION\n"
, MyTables.Select(tbl => "SELECT [col1], [col2], [col3] FROM "+ tbl)
);
注意:除非您确实希望RDBMS消除重复项,否则请考虑使用UNION ALL
运算符代替UNION
。当行数很大时,这种变化对性能的影响可能很大。
答案 1 :(得分:4)
我会做这样的事情:
Dim myTables = {"Table1", "Table2", "Table3" ... "TableN"}
Dim queries = myTables.Select(Function(tbl) "SELECT [col1], [col2], [col3] FROM " & tbl)
Return String.Join(vbNewLine & "UNION" & vbNewLine, queries)
无论如何,sql查询将占用大部分时间。从串联切换到string.join到StringBuilder的时间增益与查询执行的时间相比无差别(想想1ms vs 1000ms)。
答案 2 :(得分:0)
我建议将其附加到List<string>
并最终加入,但我不知道它会如何影响您的表现。
另一种方法是使用一个标志,显示您在第一次迭代中并在查询之前附加UNION
,而不是之后。
bool first = true;
foreach (string tbl in MyTables)
{
if (first)
first = false;
else
SQLQuery.AppendLine(" UNION ");
SQLQuery.Append("SELECT [col1], [col2], [col3] FROM ");
SQLQuery.AppendLine(tbl);
}
答案 3 :(得分:0)
如果它支持它,您可以在数据库中使用VIEW,并且所涉及的表始终相同。
但是继续使用StringBuilder方法,我将尝试用
来截断长度 SQLQuery.Lenght -= 7
ot(如果你想清楚的话)
SQLQuery.Lenght -= ("UNION"+ Environment.Newline).Length
然后我建议创建具有估计容量的StringBuilder。 例如,如果SELECT语句的平均长度为300个字符,并且您有10个表,则可以开始创建内部容量为4000个字符的StringBuilder
Dim SQLQuery = New StringBuilder(4000)
这样可以避免在添加新数据时不断扩大内部缓冲区的返工。