为什么转换 SQL MAX(DateTime) 命令在 SSMS 中有效,但在 C# 中无效?
Why does casting a SQL MAX(DateTime) command work in SSMS but not in C#?
以下查询在 Azure 托管的 SQL 数据库 table:
上的 MSSSMS 版本 18.1 中按预期工作
select Name, cast(MAX(DTStamp) as Datetime) AS Last_Seen FROM dbo.MyTable GROUP BY Name
示例输出:
Fairyflosser29 2021-11-11 19:26:00.323
GoofballAnticz 2021-11-25 14:43:57.443
WeirdAlJankyVic 2021-12-01 19:30:20.341
但是,C# 运行 中的相同 SQL 命令通过以下方法始终会从 DateTime 字段中减少毫秒数,尽管进行了强制转换,尽管我编写了强制转换的方式。这对我来说很重要,因为我的后续查询取决于 DateTime 字段的精度是否正确到毫秒,否则后续查询 return 没有。
该过程调用 GetLastSeenList()
,其中 return 是一个以逗号分隔的记录列表,表示 [=64] 中每个 Name
的最新(按日期时间戳)记录=].使用填充的列表,稍后会调用另一个方法,该方法使用这些结果来提取每个项目的完整行。
因为日期时间戳包含毫秒,所以后续查询必须包含毫秒值,否则即使有记录,查询也会失败。
首先,获取姓名列表以及他们最后一次露面的时间。接下来,为最后看到的列表中的每条记录拉出整行(此处未包括在内,因为第一个查询未提供日期时间,因为它们在 table 中 - 完整无缺毫秒)。
我不是很擅长 SQL,所以请帮助我理解我在这里遗漏了什么。
备注
1:DTStamp
列定义为 datetime
2:我已经从里到外尝试了演员表,达到了荒谬的长度,例如:cast(MAX(cast(GPS_DTStamp as Datetime)) as Datetime) ...
[编辑]: 以防万一不清楚,sql 命令 sqlcmd_GetLastSeenList
与顶部的 SSMS 查询相同:
private static readonly string sqlcmd_GetLastSeenList =
@"select Name, cast(MAX(DTStamp) as Datetime) AS Last_Seen FROM dbo.MyTable GROUP BY Name;";
GetLastSeen:
internal static async Task<string> GetLastSeenList()
{
StringBuilder sb = new StringBuilder();
var list = await ReadSQL(sqlcmd_GetLastSeenList, false);
if(list != null && list.Count > 0)
{
// Just return a CSV list of ID's with last seen timestamps
foreach(var record in list)
sb.Append($"{record[0]} {record[1]},");
}
return sb.ToString().Trim(',');
}
阅读SQL:
private static async Task<List<object[]>> ReadSQL(string cmdText, bool isProd)
{
List<object[]> response = new List<object[]>();
string connect = string.Empty;
if (isProd)
connect = await SetConnectionProd(_uidProd, _p_pwd);
else
connect = await SetConnectionTest(_uidTest, _t_pwd);
try
{
using (SqlConnection conn = new SqlConnection(connect))
{
using (SqlCommand cmd = new SqlCommand(cmdText, conn))
{
response = await ExecuteQuery2(cmd, conn);
}
}
}
catch (Exception ex)
{
//TODO: log it
throw ex;
}
return response;
}
执行查询 2:
private static async Task<List<object[]>> ExecuteQuery2(SqlCommand cmd, SqlConnection conn)
{
List<object[]> retval = new List<object[]>();
try
{
object[] myVals = new object[MAXCOLUMNCOUNT];
object[] myRow = null;
cmd.Connection.Open();
using(SqlDataReader sqlreader = cmd.ExecuteReader())
{
if(sqlreader.HasRows)
{
while(sqlreader.Read())
{
var count = sqlreader.GetValues(myVals);
myRow = new object[count];
Array.Copy(myVals, myRow, count);
retval.Add(myRow);
}
}
}
}
catch(Exception ex)
{
throw ex;
}
finally
{
cmd.Connection.Close();
}
return retval;
}
毫秒在那里。 DateTime.ToString() 默认不显示它们。例如:
var cmd = new SqlCommand("select cast('2021-11-11 19:26:00.323' as datetime) d", con);
using (var rdr = cmd.ExecuteReader())
{
rdr.Read();
var vals = new object[rdr.FieldCount];
rdr.GetValues(vals);
var val = (DateTime)vals[0];
Console.WriteLine($"{val.GetType().Name} {val} {val.ToString("O")}");
}
产出
DateTime 11/11/2021 7:26:00 PM 2021-11-11T19:26:00.3230000
但也要确保你没有在 datetime
和 datetime2
之间来回转换,例如这个
select cast(cast('2021-11-11 19:26:00.323' as datetime) as datetime2) d
产出
d
---------------------------
2021-11-11 19:26:00.3233333
这种转换可能是后续查询中错误比较的来源。
以下查询在 Azure 托管的 SQL 数据库 table:
上的 MSSSMS 版本 18.1 中按预期工作select Name, cast(MAX(DTStamp) as Datetime) AS Last_Seen FROM dbo.MyTable GROUP BY Name
示例输出:
Fairyflosser29 2021-11-11 19:26:00.323
GoofballAnticz 2021-11-25 14:43:57.443
WeirdAlJankyVic 2021-12-01 19:30:20.341
但是,C# 运行 中的相同 SQL 命令通过以下方法始终会从 DateTime 字段中减少毫秒数,尽管进行了强制转换,尽管我编写了强制转换的方式。这对我来说很重要,因为我的后续查询取决于 DateTime 字段的精度是否正确到毫秒,否则后续查询 return 没有。
该过程调用 GetLastSeenList()
,其中 return 是一个以逗号分隔的记录列表,表示 [=64] 中每个 Name
的最新(按日期时间戳)记录=].使用填充的列表,稍后会调用另一个方法,该方法使用这些结果来提取每个项目的完整行。
因为日期时间戳包含毫秒,所以后续查询必须包含毫秒值,否则即使有记录,查询也会失败。
首先,获取姓名列表以及他们最后一次露面的时间。接下来,为最后看到的列表中的每条记录拉出整行(此处未包括在内,因为第一个查询未提供日期时间,因为它们在 table 中 - 完整无缺毫秒)。
我不是很擅长 SQL,所以请帮助我理解我在这里遗漏了什么。
备注
1:
DTStamp
列定义为datetime
2:我已经从里到外尝试了演员表,达到了荒谬的长度,例如:
cast(MAX(cast(GPS_DTStamp as Datetime)) as Datetime) ...
[编辑]: 以防万一不清楚,sql 命令 sqlcmd_GetLastSeenList
与顶部的 SSMS 查询相同:
private static readonly string sqlcmd_GetLastSeenList =
@"select Name, cast(MAX(DTStamp) as Datetime) AS Last_Seen FROM dbo.MyTable GROUP BY Name;";
GetLastSeen:
internal static async Task<string> GetLastSeenList()
{
StringBuilder sb = new StringBuilder();
var list = await ReadSQL(sqlcmd_GetLastSeenList, false);
if(list != null && list.Count > 0)
{
// Just return a CSV list of ID's with last seen timestamps
foreach(var record in list)
sb.Append($"{record[0]} {record[1]},");
}
return sb.ToString().Trim(',');
}
阅读SQL:
private static async Task<List<object[]>> ReadSQL(string cmdText, bool isProd)
{
List<object[]> response = new List<object[]>();
string connect = string.Empty;
if (isProd)
connect = await SetConnectionProd(_uidProd, _p_pwd);
else
connect = await SetConnectionTest(_uidTest, _t_pwd);
try
{
using (SqlConnection conn = new SqlConnection(connect))
{
using (SqlCommand cmd = new SqlCommand(cmdText, conn))
{
response = await ExecuteQuery2(cmd, conn);
}
}
}
catch (Exception ex)
{
//TODO: log it
throw ex;
}
return response;
}
执行查询 2:
private static async Task<List<object[]>> ExecuteQuery2(SqlCommand cmd, SqlConnection conn)
{
List<object[]> retval = new List<object[]>();
try
{
object[] myVals = new object[MAXCOLUMNCOUNT];
object[] myRow = null;
cmd.Connection.Open();
using(SqlDataReader sqlreader = cmd.ExecuteReader())
{
if(sqlreader.HasRows)
{
while(sqlreader.Read())
{
var count = sqlreader.GetValues(myVals);
myRow = new object[count];
Array.Copy(myVals, myRow, count);
retval.Add(myRow);
}
}
}
}
catch(Exception ex)
{
throw ex;
}
finally
{
cmd.Connection.Close();
}
return retval;
}
毫秒在那里。 DateTime.ToString() 默认不显示它们。例如:
var cmd = new SqlCommand("select cast('2021-11-11 19:26:00.323' as datetime) d", con);
using (var rdr = cmd.ExecuteReader())
{
rdr.Read();
var vals = new object[rdr.FieldCount];
rdr.GetValues(vals);
var val = (DateTime)vals[0];
Console.WriteLine($"{val.GetType().Name} {val} {val.ToString("O")}");
}
产出
DateTime 11/11/2021 7:26:00 PM 2021-11-11T19:26:00.3230000
但也要确保你没有在 datetime
和 datetime2
之间来回转换,例如这个
select cast(cast('2021-11-11 19:26:00.323' as datetime) as datetime2) d
产出
d
---------------------------
2021-11-11 19:26:00.3233333
这种转换可能是后续查询中错误比较的来源。