我正在尝试通过调用来执行 SQL 脚本文件
ExecuteNonQuery(somefile.sql)
我得到了一个例外
SQL 数据库执行查询失败。SQL 服务器可能未运行
请帮忙。
我有一个在 C# 中执行一些文件的方法.sql
。执行第一个文件时,它确实工作正常。但是当它尝试执行下一个文件时(请参阅ExecuteFileBasedOnSequence
方法中的 else 条件),它会引发异常。我尝试在 SQL Server 上执行 SQL 脚本,它工作正常。
编辑:
这是内部异常:
错误 [42000] [Microsoft][ODBC SQL Server 驱动程序][SQL Server]“Go”附近的语法不正确
但是该脚本在 SQL Server 上运行时运行良好。
以下是 C# 代码:
private void ExecuteFileBasedOnSequence(string fileToExecute, bool executeSQLBySequence = true)
{
m_DBConnection.BeginTransaction();
if (executeSQLBySequence)
{
// Read each line of the file into a stringbuilder object to be executed individually (may throw, should just pitch out of this function)
using (StreamReader srSQL = new StreamReader(fileToExecute))
{
// Read each line of the file into a stringbuilder object to be executed individually (may throw, should just pitch out of this function)
string sqlLine;
StringBuilder sqlString = new StringBuilder();
while (!srSQL.EndOfStream)
{
sqlLine = srSQL.ReadLine();
if (string.IsNullOrEmpty(sqlLine) == false)
{
// We don't actually execute the "GO" lines but can use them to determine when to call the executenonquery function
if (string.Compare(sqlLine, "GO", true) == 0)
{
// Make sure we have something to execute
if (string.IsNullOrEmpty(sqlString.ToString()) == false)
{
m_DBConnection.ExecuteNonQuery(sqlString.ToString());
}
sqlString.Clear();
}
// Add the next line to the stringbuilder object
else
{
sqlString.AppendLine(sqlLine);
}
}
}
}
}
else
{
using (StreamReader srSQL = new StreamReader(fileToExecute))
{
if (m_DBConnection != null)
{
m_DBConnection.Open();
m_DBConnection.ExecuteNonQuery(srSQL.ReadToEnd()); //THIS ONE FAILS.
}
}
}
m_DBConnection.CommitTransaction();
}
我调用这些函数如下:
// This one works
ExecuteFileBasedOnSequence(@"Database\UpdateTriggersToSQL2017.sql");
// This one is failing
ExecuteFileBasedOnSequence(@"Database\UpgradePharmSpecScripts.sql", false);
这是失败的 SQL 文件 ( UpgradePharmSpecScripts.sql
):
Use PharmSpecDB
Go
--PC1725E-590
IF NOT EXISTS ( SELECT 23 FROM [PharmSpecDB].[dbo].[tblActivityLogMaster] WHERE Lower(strActivityLog) Like 'user rights%' AND LOWER(strActivityLogDesc) Like 'user rights%')
Begin
ALTER TABLE [PharmSpecDB].[dbo].[tblActivityLogMaster] DISABLE TRIGGER I_TRG_ACTIVITYLOGMASTER
Insert into [PharmSpecDB].[dbo].[tblActivityLogMaster](strActivityLog,bDeleted,strActivityLogDesc) values ('User rights modified', 0, 'User rights modified')
ALTER TABLE [PharmSpecDB].[dbo].[tblActivityLogMaster] ENABLE TRIGGER I_TRG_ACTIVITYLOGMASTER
End
编辑:按照建议,我删除了脚本中该行Go
之后的内容,但出现新的错误:Use PharmSpec
ExecuteNonQuery:命令文本属性尚未初始化
跟我再说一遍给后面的人听:
GO 不是 SQL 语言的一部分
这是某些工具用于在一个文件中分割多个批次的功能,但它实际上不是 SQL 本身的一部分。您不能直接将其发送到 SQL Server 或其他数据库并期望它们理解它。
看来您已经理解了这一点,因为代码正在输入中寻找该文本。但显然现有的搜索是不够的。例如,您可能仍然在行上有多余的空格。
至少在进行检查之前,您应该修剪输入(我怀疑问题是在末尾有一个多余的空格)。但同时,请注意,
Go
可能出现在文件中的原因是某些语句无法共存。您可能会发现事务并不总是合适的,有时这些批次必须来自单独的连接。UpgradePharmSpecScripts.sql
GO
我在该代码中看到的另一个问题是
IsNullOrEmpty()
循环中的检查。可能存在大量空白行。
例如,您可能有一个多行字符串文字,其中空格很重要,而现在您要跳过该文本。
举个例子,由于这看起来像是一个跨发行版本更新药房相关数据库的过程,假设您为某些药物的每个发行版提供数据,并且该数据扩展为包括默认剂量说明,其中一些说明最终会增长到涵盖多个段落。此过程现在将破坏段落分隔符。
这很重要,因为这也会影响您的批次分离器测试!
如果您有一个包含多行字符串文字的 SQL 语句,其中一行是“GO”,那么它还不够智能,无法处理该问题。
最终,如果是我,对于这种流程,我会要求每个批次都有自己的文件。如果您想要始终有效的东西,那么另一种选择是构建一个完整的 SQL 解析器。否则,您将永远玩打地鼠游戏。
最后一个选项是通过实用程序推送
sqlcmd
文件,而不是先通过 C# 运行它们。您的 C# 更新程序可能仍会协调此过程,但现在 sqlcmd 实用程序可以处理批处理问题。当然,这意味着从具有 sqlcmd 的工作站运行更新,而 Windows 默认情况下并非如此。