如何在SQL查询中合并多列(年/月/日/时/分)转换为SMALLDATETIME并实现日期范围查询
如何在SQL查询中合并多列(年/月/日/时/分)转换为SMALLDATETIME并实现日期范围查询
没问题,我来帮你搞定这个需求!你想把分散的年、月、日、时、分列合并成SMALLDATETIME来做范围查询,这个思路完全可行,而且有几种简单的实现方式,我给你一步步讲清楚。
首先:把多列合并为SMALLDATETIME的方法
因为你的DateAndTimeTable里有TSYear(smallint)、TSMonth/TSDay/TSHour/TSMinute(tinyint),刚好可以组合成带分钟精度的时间,而SMALLDATETIME正好支持到分钟(秒会被截断),完美匹配。
方法1:用DATEFROMPARTS + TIME拼接(推荐,SQL Server 2012+)
这个方法最直观,也不容易出错:
-- 组合年月日为DATE,再拼接时分的TIME,最后转成SMALLDATETIME CAST( DATEFROMPARTS(tsr.TSYear, tsr.TSMonth, tsr.TSDay) + CAST(CAST(tsr.TSHour AS VARCHAR(2)) + ':' + CAST(tsr.TSMinute AS VARCHAR(2)) AS TIME(0)) AS SMALLDATETIME)
DATEFROMPARTS会直接把年、月、日转成合法的DATE类型,再加上用时分拼接的TIME,最后转成SMALLDATETIME就得到了完整的时间值。
方法2:拼接字符串后转换(兼容低版本SQL Server)
如果你的SQL Server版本低于2012(不支持DATEFROMPARTS),可以把各列拼接成标准的时间字符串再转换,注意要补零避免解析错误:
CAST( CONCAT( tsr.TSYear, '-', RIGHT('0' + CAST(tsr.TSMonth AS VARCHAR(2)), 2), '-', RIGHT('0' + CAST(tsr.TSDay AS VARCHAR(2)), 2), ' ', RIGHT('0' + CAST(tsr.TSHour AS VARCHAR(2)), 2), ':', RIGHT('0' + CAST(tsr.TSMinute AS VARCHAR(2)), 2) ) AS SMALLDATETIME )
这里用RIGHT('0' + ..., 2)确保月份、日期、小时、分钟都是两位(比如1月变成01),避免SQL解析时出错。
然后:重构你的查询实现日期范围查询
另外,强烈建议你不要用字符串拼接SQL语句,这会导致SQL注入风险,而且维护起来麻烦。改用参数化查询才是最佳实践。
下面是完整的重构代码,假设你有startDate和endDate两个.NET DateTime参数:
// 定义参数化SQL语句 string sqlQuery = @" SELECT DISTINCT dbd.ElementID FROM [DatabaseName].[dbo].[DataTable] dbd JOIN [DatabaseName].[dbo].[DateAndTimeTable] tsr ON tsr.AccessionID = dbd.AccessionID WHERE -- 组合时间并判断是否在范围之内 CAST( DATEFROMPARTS(tsr.TSYear, tsr.TSMonth, tsr.TSDay) + CAST(CAST(tsr.TSHour AS VARCHAR(2)) + ':' + CAST(tsr.TSMinute AS VARCHAR(2)) AS TIME(0)) AS SMALLDATETIME) BETWEEN @StartDate AND @EndDate AND ISNUMERIC(LEFT(dbd.ElementID, 2)) = 1 ORDER BY dbd.ElementID"; // 使用参数化查询,避免SQL注入 using (var command = new SqlCommand(sqlQuery, new SqlConnection(DataConnectionString))) { command.Parameters.AddWithValue("@StartDate", startDate); command.Parameters.AddWithValue("@EndDate", endDate); command.Connection.Open(); DataTable dataTable = new DataTable(); dataTable.Load(command.ExecuteReader()); }
一些额外提示
- 如果你的
endDate是包含当天最后一分钟的,比如你想包含到2024-05-20 23:59,可以直接传入对应的DateTime;如果传入的是2024-05-21 00:00,那么BETWEEN会排除2024-05-20的最后一分钟,这点要注意。 - 如果你需要用到索引优化查询,最好考虑在
DateAndTimeTable里计算并存储这个组合后的SMALLDATETIME列(比如加一个计算列),这样查询时不需要每次都转换,性能会更好。
内容来源于stack exchange
相关产品推荐
相关产品推荐

