SQL Query 和 SqlClient 操作的区别
Difference between SQL Query and SqlClient operation
我正在尝试使用存储过程从 SQL Server 2008 R2 数据库中查询数据。代码执行无误,但查询未返回任何结果。当通过 SQL Server Management Studio 使用完全相同的参数调用相同的存储过程时,会正确返回数据。我不知道是什么原因导致的,可能是 SqlClient 实现的特定原因?查询returns两个DateTime2
值之间的所有数据;如果我使这些 DateTime2
值相距足够远,则会返回数据。显然这不是期望的行为。
C# 代码(startTime.HasValue
和 endTime.HasValue
在这种情况下为真):
if (conn.State == ConnectionState.Closed)
{
conn.Open();
}
SqlCommand comm = conn.CreateCommand();
comm.CommandType = CommandType.StoredProcedure;
comm.CommandText = "GetAllPropertyValues";
comm.Parameters.Add("@dataTypeName", SqlDbType.NVarChar).Value = dataTypeName;
comm.Parameters.Add("@propertyName", SqlDbType.NVarChar).Value = propertyName;
if (startTime.HasValue)
{
var startString = startTime.Value.ToUniversalTime().ToString("O");
if (endTime.HasValue)
{
var endString = endTime.Value.ToUniversalTime().ToString("O");
comm.CommandText += "Between";
comm.Parameters.Add("@startTime", SqlDbType.DateTime2).Value = startString;
comm.Parameters.Add("@endTime", SqlDbType.DateTime2).Value = endString;
}
else
{
comm.CommandText += "After";
comm.Parameters.Add("@dateTime", SqlDbType.DateTime2).Value = startString;
}
}
SqlDataReader reader = comm.ExecuteReader();
while (reader.Read())
{
// ...
}
SQL 服务器存储过程:
declare @str varchar(max) = 'select * from [dbo].[' + @tableName + '] where StartTime BETWEEN ''' +
CAST(@startTime as nvarchar(max)) + ''' AND ''' + CAST(@endTime as nvarchar(max)) + ''' order by StartTime asc'
exec(@str)
执行的示例查询:
USE [Construct3]
GO
DECLARE @return_value int
EXEC @return_value = [dbo].[GetAllPropertyValuesBetween]
@datatypeName = N'HeadPose',
@propertyName = N'HeadRotationRadiansZ',
@startTime = '2014-12-31T19:00:00.0000000Z',
@endTime = '2014-12-31T20:00:00.0000000Z'
SELECT 'Return Value' = @return_value
GO
更改 CommandText
属性 会清除 Parameters
集合。完成文本后设置所有参数。
此外,您所拥有的将容易受到 sql 注入攻击。您应该使用 sp_executesql
,而不是 exec()
,以便您的时间参数得到安全处理。我会给你一个疑问,即 @tableName
参数不是用户可以输入任意文本的地方,而是必须从服务器验证的表列表中进行选择。
假设存储过程中的 @startTime
和 @endTime
参数类型为 DATETIME
那么您要进行从日期时间到字符串的双重转换,首先是在您的 C# 代码:
var startString = startTime.Value.ToUniversalTime().ToString("O"); //This will create the datetime as a string using .NET format
您将它作为 DateTime2
:
传递给存储过程
comm.Parameters.Add("@startTime", SqlDbType.DateTime2).Value = startString;
然后在 SQL 上将其转换回字符串格式:
CAST(@startTime as nvarchar(max))
这可能是问题所在,当您在 .NET 和 SQL 中进行从 DATETIME
到字符串的转换时,不要期望它们有相同的结果,所以当您执行存储数据库上的过程你得到了结果,但是当你从 .NET 调用它时,没有结果,因为日期是错误的。我建议做的是将这些日期参数的值作为普通 .NET DateTime
值传递,并在存储过程中将其转换为 varchar
。您可以使用 SQL 中的 CONVERT
函数来实现这一点,查看 this link 了解有关 CONVERT
日期格式的更多信息。
希望这对您有所帮助。
我正在尝试使用存储过程从 SQL Server 2008 R2 数据库中查询数据。代码执行无误,但查询未返回任何结果。当通过 SQL Server Management Studio 使用完全相同的参数调用相同的存储过程时,会正确返回数据。我不知道是什么原因导致的,可能是 SqlClient 实现的特定原因?查询returns两个DateTime2
值之间的所有数据;如果我使这些 DateTime2
值相距足够远,则会返回数据。显然这不是期望的行为。
C# 代码(startTime.HasValue
和 endTime.HasValue
在这种情况下为真):
if (conn.State == ConnectionState.Closed)
{
conn.Open();
}
SqlCommand comm = conn.CreateCommand();
comm.CommandType = CommandType.StoredProcedure;
comm.CommandText = "GetAllPropertyValues";
comm.Parameters.Add("@dataTypeName", SqlDbType.NVarChar).Value = dataTypeName;
comm.Parameters.Add("@propertyName", SqlDbType.NVarChar).Value = propertyName;
if (startTime.HasValue)
{
var startString = startTime.Value.ToUniversalTime().ToString("O");
if (endTime.HasValue)
{
var endString = endTime.Value.ToUniversalTime().ToString("O");
comm.CommandText += "Between";
comm.Parameters.Add("@startTime", SqlDbType.DateTime2).Value = startString;
comm.Parameters.Add("@endTime", SqlDbType.DateTime2).Value = endString;
}
else
{
comm.CommandText += "After";
comm.Parameters.Add("@dateTime", SqlDbType.DateTime2).Value = startString;
}
}
SqlDataReader reader = comm.ExecuteReader();
while (reader.Read())
{
// ...
}
SQL 服务器存储过程:
declare @str varchar(max) = 'select * from [dbo].[' + @tableName + '] where StartTime BETWEEN ''' +
CAST(@startTime as nvarchar(max)) + ''' AND ''' + CAST(@endTime as nvarchar(max)) + ''' order by StartTime asc'
exec(@str)
执行的示例查询:
USE [Construct3]
GO
DECLARE @return_value int
EXEC @return_value = [dbo].[GetAllPropertyValuesBetween]
@datatypeName = N'HeadPose',
@propertyName = N'HeadRotationRadiansZ',
@startTime = '2014-12-31T19:00:00.0000000Z',
@endTime = '2014-12-31T20:00:00.0000000Z'
SELECT 'Return Value' = @return_value
GO
更改 CommandText
属性 会清除 Parameters
集合。完成文本后设置所有参数。
此外,您所拥有的将容易受到 sql 注入攻击。您应该使用 sp_executesql
,而不是 exec()
,以便您的时间参数得到安全处理。我会给你一个疑问,即 @tableName
参数不是用户可以输入任意文本的地方,而是必须从服务器验证的表列表中进行选择。
假设存储过程中的 @startTime
和 @endTime
参数类型为 DATETIME
那么您要进行从日期时间到字符串的双重转换,首先是在您的 C# 代码:
var startString = startTime.Value.ToUniversalTime().ToString("O"); //This will create the datetime as a string using .NET format
您将它作为 DateTime2
:
comm.Parameters.Add("@startTime", SqlDbType.DateTime2).Value = startString;
然后在 SQL 上将其转换回字符串格式:
CAST(@startTime as nvarchar(max))
这可能是问题所在,当您在 .NET 和 SQL 中进行从 DATETIME
到字符串的转换时,不要期望它们有相同的结果,所以当您执行存储数据库上的过程你得到了结果,但是当你从 .NET 调用它时,没有结果,因为日期是错误的。我建议做的是将这些日期参数的值作为普通 .NET DateTime
值传递,并在存储过程中将其转换为 varchar
。您可以使用 SQL 中的 CONVERT
函数来实现这一点,查看 this link 了解有关 CONVERT
日期格式的更多信息。
希望这对您有所帮助。