You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

C#拼接SQL按日期筛选报字符串转日期/时间失败异常如何修复

异常根因

你遇到的日期转换异常是直接拼接DateTime值到SQL字符串导致的:

  • C#中将dtFrom.Value、dtTo.Value直接拼入字符串时,会默认使用当前操作系统的区域设置格式化日期,可能生成2024/5/20、5/20/2024、2024年5月20日等不同格式的字符串
  • SQL Server服务端解析日期字符串时使用自身的区域配置,一旦和客户端拼接出的格式不匹配,就会抛出"Conversion failed when converting date and/or time from character string"异常
  • 除此之外,字符串拼接SQL还存在SQL注入风险,原代码的日期范围逻辑也有漏洞:DateTimePicker默认带当前时分秒,若结束日期未手动选到23:59:59,会漏掉结束日当天的大部分数据。
修复方案

核心是改用参数化查询,完全跳过日期转字符串的环节,同时修正日期范围逻辑、补上资源释放处理,修复后完整代码如下:

public void LoadSold()
{
    int i = 0;
    double total = 0;
    dgvSold.Rows.Clear();

    // 抽取公共SQL片段,减少重复代码
    string querySql = @"SELECT c.CartID, c.transno, c.ProductID, p.ProdDescription, c.price, c.qty, c.disc, c.total 
                        FROM tbCart AS c 
                        INNER JOIN Product AS p ON c.ProductID = p.ProductID 
                        WHERE status = 'Sold' 
                        AND sdate >= @StartDate AND sdate < @EndDate";

    // 非全量查询场景追加收银员筛选条件
    if (cboSales.Text != "All Sales")
    {
        querySql += " AND cashier LIKE @Cashier";
    }

    // using块自动释放数据库资源,避免异常时连接泄漏
    using (con)
    {
        con.Open();
        using (SqlCommand command = new SqlCommand(querySql, con))
        {
            // 日期参数直接传DateTime类型,无需手动转字符串,彻底规避格式不匹配问题
            command.Parameters.Add("@StartDate", SqlDbType.DateTime).Value = dtFrom.Value.Date;
            // 结束时间取选中日期次日0点,覆盖结束日全天所有数据,比BETWEEN逻辑更严谨
            command.Parameters.Add("@EndDate", SqlDbType.DateTime).Value = dtTo.Value.Date.AddDays(1);

            if (cboSales.Text != "All Sales")
            {
                command.Parameters.Add("@Cashier", SqlDbType.NVarChar).Value = $"%{cboSales.Text}%";
            }

            using (SqlDataReader dr = command.ExecuteReader())
            {
                while (dr.Read())
                {
                    i++;
                    total += Convert.ToDouble(dr["total"]);
                    dgvSold.Rows.Add(i, dr[0].ToString(), dr[1].ToString(), dr[2].ToString(), dr[3].ToString(), dr[4].ToString(), dr[5].ToString(), dr[6].ToString(), dr[7].ToString());
                }
            }
        }
        con.Close();
    }

    lblTotal.Text = total.ToString("#,##0.00");
}
关键改动说明
  • 所有动态传入SQL的值都通过SqlParameter传递,日期类型直接传结构体值,ADO.NET会自动处理和SQL Server的类型匹配,完全不会再出现字符串转日期的格式错误,同时彻底堵上SQL注入漏洞。
  • 日期范围改用>= 起始日0点、< 结束日次日0点的判断逻辑,不需要手动调整时分秒就能覆盖选中时段的全部数据,避免BETWEEN的边界遗漏问题。
  • 原代码中status LIKE 'Sold'没有通配符,等价于等值判断,直接改为status = 'Sold'执行效率更高。
  • 增加using块包裹连接、命令、数据读取器对象,即使执行过程中抛出异常也能自动释放非托管资源,不会出现连接池占满的问题。

内容的提问来源于stack exchange,提问作者yannis

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.26 10:54:15