我从事 ASP.NET Web 表单项目;我无法在日期时间列上获取两个时间(时间从和时间到)之间的数据。
C#函数
public DataTable GetDataForSearch(string datelogged, string FromTime, string ToTime)
{
string response = string.Empty;
SqlCommand cmd = new SqlCommand();
DataTable dt = new DataTable();
try
{
conn.Open();
cmd.Connection = conn;
cmd.CommandText = "select datelogged AS EntredDatetime, Doc_type AS OrderType, Printer_name, BranchID AS BranchCode, Status, id from Print_Report where cast(datelogged as date)=@datelogged and and FORMAT(CAST(datelogged AS DATETIME), 'HH:mm')>'@FromTime' AND FORMAT(CAST(datelogged AS DATETIME), 'HH:mm')<@ToTime";
cmd.CommandType = CommandType.Text;
cmd.CommandTimeout = 50000;
cmd.Parameters.AddWithValue("@datelogged", datelogged);
cmd.Parameters.AddWithValue("@FromTime", FromTime);
cmd.Parameters.AddWithValue("@ToTime", ToTime);
SqlDataAdapter sda = new SqlDataAdapter(cmd);
sda.Fill(dt);
}
catch (Exception ex)
{
response = ex.Message;
}
finally
{
cmd.Dispose();
conn.Close();
}
return dt;
}
当我从 SQL Server 尝试时,它返回 2 行:
select
datelogged as EntredDatetime, Doc_type as OrderType,
Printer_name, BranchID as BranchCode, Status, id
from
Print_Report
where
BranchID = '10207'
and cast(datelogged as date) = '2010-07-05'
and Doc_type = 'BP'
and format(cast(datelogged as DATETIME), 'HH:mm') > '13:30'
and format(cast(datelogged as DATETIME), 'HH:mm') < '14:00'
预期结果:
我将查询修改为如下:
cmd.CommandText = "select datelogged AS EntredDatetime, Doc_type AS OrderType, Printer_name, BranchID AS BranchCode, Status, id from Print_Report where BranchID=@BranchCode and cast(datelogged as date)=@datelogged and Doc_type=@OrderType and FORMAT(CAST(datelogged AS DATETIME), 'HH:mm')>='@FromTime' AND FORMAT(CAST(datelogged AS DATETIME), 'HH:mm')<='@ToTime'";
但仍然没有得到任何结果 那么我要做什么来解决问题
始终声明要传递到 SQL 中的参数类型。不要依赖 sql 来推断它。还要养成将数据库连接包装在
Using
块中的习惯。
cmd.Parameters.Add("@datelogged", sqldbtype.datetime).value = datelogged;
cmd.Parameters.Add("@FromTime", sqldbtype.time).value = FromTime;
cmd.Parameters.Add("@ToTime", Sqldbtype.time).value = ToTime;
您还需要为 @branch 和 @ordertype 参数添加代码。
您的 SQL 将如下所示。编写 SQL 时,大多数错误都可以通过在编写 SQL 时一致地格式化 SQL 来解决。当您像上面那样声明参数的数据类型时,参数不需要用引号引起来。它会为你处理这一切。我没有单独比较日期,而是选择将时间作为时间数据类型传递,然后将它们转换为查询中的日期时间。从那里,您可以将两个日期时间与
+
一起添加,然后以相同的方式进行比较。如果您决定将传入/传出值作为日期时间传递,则只需删除顶部的声明行即可。
您可以在
BETWEEN
子句中使用 WHERE
,但这由您自行决定。
DECLARE @To DATETIME = (@datelogged + CAST(@ToTime AS DATETIME)), @From DATETIME = (@datelogged + CAST(@FromDate AS DATETIME));
SELECT
datelogged AS EntredDatetime,
Doc_type AS OrderType,
Printer_name,
BranchID AS BranchCode,
Status,
ID
FROM Print_Report
WHERE BranchID = @BranchCode AND
Doc_type = @OrderType AND
datelogged >= @From AND
datelogged <= @To
那么,有几件事:
不要将长行代码换行,它们很容易出错。
查看您的 SQL,您有以下内容:
select datelogged AS EntredDatetime, Doc_type AS OrderType, Printer_name,
BranchID AS BranchCode, Status, id from Print_Report
where cast(datelogged as date)=@datelogged
and and FORMAT(CAST(datelogged AS DATETIME), 'HH:mm')>'@FromTime'
AND FORMAT(CAST(datelogged AS DATETIME), 'HH:mm')<@ToTime"
请注意,现在我们在 SQL 中看到“and and”是多么容易。
并且不要在 SQL 中执行这些转换,因为它很混乱,但是这样的表达式无法索引,并且它们运行速度会很慢(此外,它使 SQL 处理起来相当混乱)。
下一步:考虑将内联 SQL 移出到存储过程,但更好(并且更少的精力和工作)是使用视图,因此比存储过程“更少”工作,您可以使用查询生成器/designer,更好的是多个例程可以使用该一个“视图”。你仍然使用内联SQL,但只是说
select * from vPrint_Report
WHERE datelogged is BETWEEN @dtStart AND @dtEnd";
接下来:不要使用带有值的 add - 使用强类型参数。
下一步:不推荐使用
Parameters.Add("some param", "some value")
,因为第二个参数可能与 int 作为 dbtype 混淆?
不推荐使用带有“ADD”的类型化参数!事实上,我建议使用
.ADD("@ParmName", sqlDbType.int).Value =
仅上面第二个参数具有非 dbtype 的重载已被弃用!
接下来:
您没有显示该连接对象的创建位置。不要尝试创建一些全局范围的连接对象。虽然在“网络时代”之前,为了性能,是的,我们经常“坚持”一个连接对象,但是基于网络,有一个自动“连接”池,因此标准是每次都重新创建连接,并让系统自动为您处理。通过这样做,您可以利用 .net 基于网络的系统中的“自动”连接系统。
每次重新创建连接对象不会影响性能,因为连接池将“查找”并使用缓存的连接 - 它运行速度很快 - 每次都可以随意重新创建连接对象。
你如何让系统为你管理这个?当然,为什么你总是将代码包装在 using 块中。在您的示例中,您仅在代码错误时处理连接,但在成功时不处理连接。
接下来:
如上所述,不要尝试解析或转换 SQL 中的日期和日期时间,而是为开始日期和结束日期(均带有时间)提供 STRONG 类型。这样的代码不仅不那么混乱,而且代码中的工作也“很小”,但 SQL 变得不那么混乱了。因此,我们用少量代码换取了干净 SQL 的巨大好处。
所以,让我们学习上述所有课程,现在我们明白了:
public DataTable GetDataForSearch(string datelogged, string FromTime, string ToTime)
{
DataTable dt = new DataTable();
string strCon = Properties.Settings.Default.TEST4; // change to YOUR connection
using (SqlConnection conn = new SqlConnection(strCon))
{
string strSQL =
@"select datelogged AS EntredDatetime, Doc_type AS OrderType,
Printer_name, BranchID AS BranchCode, Status, id
FROM Print_Report
WHERE datelogged is BETWEEN @dtStart AND @dtEnd";
DateTime dtDate = DateTime.Parse(datelogged);
DateTime dtFromTime = DateTime.Parse(FromTime);
DateTime dtToTime = DateTime.Parse(ToTime);
DateTime dtStart =
dtDate.Add(new TimeSpan(dtFromTime.Hour, dtFromTime.Minute, dtFromTime.Second));
DateTime dtEnd =
dtDate.Add(new TimeSpan(dtToTime.Hour, dtToTime.Minute, dtToTime.Second));
using (SqlCommand cmd = new SqlCommand(strSQL, conn))
{
cmd.Parameters.Add("@dtStart", SqlDbType.DateTime).Value = dtStart;
cmd.Parameters.Add("@dtEnd", SqlDbType.DateTime).Value = dtEnd;
try
{
conn.Open();
dt.Load(cmd.ExecuteReader());
}
}
}
return dt;
}
因此,请注意我们如何让系统“关闭”连接并处理它。即使代码出错,即使没有被捕获,连接和命令对象也将被正确处理和管理 - 在所有情况下!
另外,请注意如何在代码方面付出一些努力来获取强类型日期开始和结束,从而使 SQL 部分的工作量减少很多,但更重要的是也意味着我们使用 + 享受参数的强类型值,我们喜欢使用高速索引。