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

VB.NET调用SQL Server参数化INSERT报110错误:列数与VALUES值数不匹配

问题描述

我的VB.NET应用的一位瑞典用户反馈执行查询时出现错误#110,错误信息为There are fewer columns in the INSERT statement than values specified in the VALUES clause.,他发来的报错截图如下:
Error 110

报错信息的结构如下:

$"DoSql Error #{ex.Number}: {ex.Message}; sql: {sql}; Item={iType}:{iNo}:{iColor}:{iCond}"

我在VB.NET中使用参数化查询调用SQL Server插入语句,指定插入18列,未使用字符串插值,相关代码如下:

Private Sub UpdatePrices(iNo As String, iType As String, iColor As Integer, iCond As String)
... 'Retrieve pgonline Json result from web server '
Dim sqlParams = GetParams({
        {"@Item", iNo},
        {"@Color", iColor},
        {"@Cond", iCond},
        {"@Type", iType}},
        {"@Curr", pgOnline("currency_code").ToString},
        {"@SoldMinPrice", pgOnline("min_price").Value(Of Single)},
        {"@SoldMaxPrice", pgOnline("max_price").Value(Of Single)},
        {"@SoldAvgPrice", pgOnline("avg_price").Value(Of Single)},
        {"@SoldQtyAvgPrice", pgOnline("qty_avg_price").Value(Of Single)},
        {"@SoldLotQty", Math.Min(32767, pgOnline("unit_quantity").Value(Of Integer))},
        {"@SoldItemQty", Math.Min(32767, pgOnline("total_quantity").Value(Of Integer))},
        {"@StockMinPrice", pgOnline("min_price").Value(Of Single)},
        {"@StockMaxPrice", pgOnline("max_price").Value(Of Single)},
        {"@StockAvgPrice", pgOnline("avg_price").Value(Of Single)},
        {"@StockQtyAvgPrice", pgOnline("qty_avg_price").Value(Of Single)},
        {"@StockLotQty", pgOnline("unit_quantity").Value(Of Integer)},
        {"@StockItemQty", Math.Min(32767, pgOnline("total_quantity").Value(Of Integer))}
            }))
Dim sql = "INSERT INTO [Bricklink].[Price_Guide] (PriceDate,ItemNo,ItemType,Color,Cond,Curr,SoldMinPrice,SoldMaxPrice,SoldAvgPrice,SoldQtyAvgPrice,
  SoldLotQty,  SoldItemQty,  StockMinPrice,  StockMaxPrice,  StockAvgPrice,  StockQtyAvgPrice,  StockLotQty,  StockItemQty) 
VALUES(CURRENT_TIMESTAMP, @Item, @Type, @Color, @Cond, @Curr, @SoldMinPrice, @SoldMaxPrice, @SoldAvgPrice, @SoldQtyAvgPrice, 
  @SoldLotQty, @SoldItemQty, @StockMinPrice, @StockMaxPrice, @StockAvgPrice, @StockQtyAvgPrice, @StockLotQty, @StockItemQty);"
DoSql(sql, sqlParams, True)

INSERT语句和VALUES子句均包含18个列,参数混合为.NET的Single或Integer数值类型,数据从服务端拉取:我在美国本地拉取时,Single类型的价格无千位分隔符,保留3位小数。

需要注意的是我本地从未遇到该错误,该价格更新查询每日在本地运行数千次,瑞典用户是少数非美国用户之一。我猜测是瑞典地区的数据结构差异或设备数据解析逻辑差异,导致SQL Server误读数值:原本猜想数值中的逗号会被识别为字段分隔符,让SQL认为VALUES中的列数多于INSERT指定列数。

但我在本地测试将小数点替换为逗号时,仅会触发算术溢出错误,不会将数值中的逗号识别为查询语句的分隔符;且无销售数据时服务端所有字段返回0,不存在空值或空白值。

想确认三个问题:

  • 参数化查询的参数是否可能触发此类行为?
  • 若可能,我该如何修改查询解决该问题?
  • 若不可能,还有哪些差异可能导致SQL Server认为该INSERT、VALUES均为18列的查询存在列数不匹配问题?

附录

查询调用方法DoSql的实现代码如下:

Public Function DoSql(sql As String, Optional ByVal params As List(Of SqlParameter) = Nothing, Optional throwException As Boolean = False) As Boolean
    Using conn As New SqlConnection(GetDBConnectionString)
        Return DoSql(conn, sql, params, throwException)
    End Using
End Function
Public Function DoSql(conn As SqlConnection, sql As String, Optional ByVal params As List(Of SqlParameter) = Nothing, Optional throwException As Boolean = False) As Boolean
    Dim cmd As New SqlCommand(sql, conn)
    If Not IsNothing(params) Then
        For Each param In params
            cmd.Parameters.Add(param)
        Next
    End If
    If cmd.Connection.State <> ConnectionState.Open Then cmd.Connection.Open()
    Try
        Dim rows As Integer = cmd.ExecuteNonQuery()

        cmd.Parameters.Clear()
        Return (rows > 0)
    Catch ex As SqlException
        Dim paramStg As String = ""
        If params IsNot Nothing Then
            For Each param In params
                paramStg += param.ParameterName & "=" & param.Value.ToString & "; "
            Next
        End If
        Log($"DoSql Error {ex.Number}: {ex.Message} executing: {sql} with params={paramStg}", 2)
        cmd.Parameters.Clear()
        If throwException Then Throw ex
        MsgBoxASync($"DoSql Error #{ex.Number}: {ex.Message}; parameters: {paramStg}; sql: {sql}")
        Return False
    Catch ex As Exception
        Dim paramStg As String = ""
        If params IsNot Nothing Then
            For Each param In params
                paramStg += param.ParameterName & "=" & param.Value.ToString & "; "
            Next
        End If
        Log($"Error {ex.Message} occured executing the DoSQL command {sql} with params={paramStg}", 2)
        cmd.Parameters.Clear()
        Return False
    End Try
End Function

解答
  1. 参数化查询本身不可能触发此类行为。参数化查询的参数值是独立于SQL语句文本传输的,不会和SQL本体拼接,无论参数值包含逗号、引号还是其他特殊字符,都不会被SQL Server解析为SQL语法的一部分,你本地的测试结果也验证了这一点。
  2. 该场景不需要针对参数化查询本身做修改,可按下面的排查方案定位问题。
  3. 可能导致该错误的差异点如下:
    • 表结构不一致:确认瑞典用户连接的数据库实例中[Bricklink].[Price_Guide]表结构和你本地完全一致,包括列的数量、顺序,部分用户如果使用本地自建库,可能存在表结构未同步更新的情况。
    • GetParams方法逻辑缺陷:如果该方法内部没有显式给SqlParameter指定SqlDbType,在瑞典区域的文化设置下,数值类型的参数可能被自动推断为字符串类型,若同时存在JSON解析错误导致返回的字段数量异常,可能生成错误的参数列表。
    • SQL语句存在隐藏特殊字符:你编写的INSERT语句中如果包含全角空格、不可见控制字符,在瑞典区域的系统编码下可能被SQL Server错误识别为值分隔符,导致VALUES子句被拆分为更多项。
    • JSON解析异常:瑞典用户拉取的服务端返回结果如果存在格式异常,pgOnline读取字段时触发静默错误,导致部分参数的实际值为异常类型,间接触发SQL执行逻辑异常。

修复建议

  • 先让报错用户导出弹窗中的完整SQL和参数内容,手动统计INSERT后的列数、VALUES后的项数,确认是否真的存在数量不一致的情况。
  • 修改参数创建逻辑,给每个参数显式指定对应的SqlDbType,例如Single类型指定为SqlDbType.Real,Integer类型指定为SqlDbType.Int,避免自动类型推断异常。
  • 在调用DoSql方法前增加临时日志,输出完整的SQL语句文本、参数数量、每个参数的类型和值,确认执行前的逻辑和预期一致。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.04 10:21:00