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

SQL Server解析JSON时nvarchar转decimal报错求助

问题解决:JSON解析时quantity字段类型转换错误

问题背景

使用指定SQL解析JSON文件时,单条测试数据可正常运行,但包含1000条数据的文件触发错误:

Error converting data type nvarchar to decimal.

经排查问题出在quantity字段,移除该字段后可正常返回全部数据,但业务需要保留该字段。

原SQL语句:

SELECT 
    A.subscription_id   AS subscriptionid,
    A.customer_id       AS customerid,
    A.customer_domain   AS customerdomain,
    A.mpn_id            AS mpnid,
    A.resource_group    AS resourcegroup,
    A.resource_name     AS resourcename,
    A.resource_type     AS resourcetype,
    A.[resource region] AS resourceregion,
    A.meter_id          AS meterid,
    A.meter_name        AS metername,
    A.meter_category    AS metercategory,
    A.meter_subcategory AS metersubcategory,
    A.unit              AS unit,
    A.quantity          AS quantity,
    A.msrp              AS msrp,
    A.unit_price        AS unitprice,
    A.billing_cycle     AS billingcycle,
    A.usage_date        AS usagedate,
    A.resource_tags     AS resourcetags,
    B.contract_no       AS contractno,
    B.contract_line_no  AS contractlineno,
    B.eu_no             AS euno,
    B.eu_name           AS euname
FROM
    OPENJSON(@json, '$.body."items"')
    WITH(
        subscription_id     VARCHAR(50),
        customer_id         VARCHAR(50),
        customer_domain     VARCHAR(50),
        mpn_id              VARCHAR(50),
        resource_group      VARCHAR(50),
        resource_name       VARCHAR(50),
        resource_type       VARCHAR(50),
        [resource region]   VARCHAR(50),
        meter_id            VARCHAR(50),
        meter_name          VARCHAR(50),
        meter_category      VARCHAR(50),
        meter_subcategory   VARCHAR(50),
        unit                VARCHAR(50),
        quantity            DECIMAL(18,8),
        msrp                DECIMAL(18,8),
        unit_price          DECIMAL(18,8),
        billing_cycle       VARCHAR(50),
        usage_date          VARCHAR(50),
        resource_tags       VARCHAR(50),
        subscription_contract_ref   NVARCHAR(MAX) as JSON
    ) AS A
CROSS APPLY 
    OPENJSON(A.subscription_contract_ref)
    WITH(
        contract_no         INT,
        contract_line_no    INT,
        eu_no               INT,
        eu_name             VARCHAR(50)
    ) as B

解决方案

错误原因是某条数据的quantity字段值无法直接转换为DECIMAL(18,8)(比如是字符串格式数字、null、包含非数字字符等),可通过以下两种方式处理:

方法1:安全转换避免查询中断

修改OPENJSON的WITH子句,先将quantity读取为字符串类型,再用TRY_CONVERT做安全转换(转换失败时返回NULL,而非抛出错误):

SELECT 
    A.subscription_id   AS subscriptionid,
    A.customer_id       AS customerid,
    A.customer_domain   AS customerdomain,
    A.mpn_id            AS mpnid,
    A.resource_group    AS resourcegroup,
    A.resource_name     AS resourcename,
    A.resource_type     AS resourcetype,
    A.[resource region] AS resourceregion,
    A.meter_id          AS meterid,
    A.meter_name        AS metername,
    A.meter_category    AS metercategory,
    A.meter_subcategory AS metersubcategory,
    A.unit              AS unit,
    -- 安全转换quantity,失败返回NULL;如需默认值可改为ISNULL(TRY_CONVERT(...), 0)
    TRY_CONVERT(DECIMAL(18,8), A.quantity) AS quantity,
    TRY_CONVERT(DECIMAL(18,8), A.msrp) AS msrp,
    TRY_CONVERT(DECIMAL(18,8), A.unit_price) AS unitprice,
    A.billing_cycle     AS billingcycle,
    A.usage_date        AS usagedate,
    A.resource_tags     AS resourcetags,
    B.contract_no       AS contractno,
    B.contract_line_no  AS contractlineno,
    B.eu_no             AS euno,
    B.eu_name           AS euname
FROM
    OPENJSON(@json, '$.body."items"')
    WITH(
        subscription_id     VARCHAR(50),
        customer_id         VARCHAR(50),
        customer_domain     VARCHAR(50),
        mpn_id              VARCHAR(50),
        resource_group      VARCHAR(50),
        resource_name       VARCHAR(50),
        resource_type       VARCHAR(50),
        [resource region]   VARCHAR(50),
        meter_id            VARCHAR(50),
        meter_name          VARCHAR(50),
        meter_category      VARCHAR(50),
        meter_subcategory   VARCHAR(50),
        unit                VARCHAR(50),
        -- 先读取为字符串类型
        quantity            NVARCHAR(50),
        msrp                NVARCHAR(50),
        unit_price          NVARCHAR(50),
        billing_cycle       VARCHAR(50),
        usage_date          VARCHAR(50),
        resource_tags       VARCHAR(50),
        subscription_contract_ref   NVARCHAR(MAX) as JSON
    ) AS A
CROSS APPLY 
    OPENJSON(A.subscription_contract_ref)
    WITH(
        contract_no         INT,
        contract_line_no    INT,
        eu_no               INT,
        eu_name             VARCHAR(50)
    ) as B

方法2:定位并修复异常数据

如果需要找出具体的错误记录,可以先读取quantity为字符串,筛选出无法转换的条目:

SELECT 
    A.subscription_id,
    A.quantity,
    -- 其他需排查的字段可按需添加
    A.subscription_contract_ref
FROM
    OPENJSON(@json, '$.body."items"')
    WITH(
        subscription_id     VARCHAR(50),
        quantity            NVARCHAR(50),
        subscription_contract_ref   NVARCHAR(MAX) as JSON
    ) AS A
WHERE TRY_CONVERT(DECIMAL(18,8), A.quantity) IS NULL
  AND A.quantity IS NOT NULL

找到异常数据后,修正JSON中的对应值(比如将非数字内容改为合法数值),再用原SQL解析即可。

说明

  • TRY_CONVERT支持SQL Server 2012及以上版本,会尝试转换数据类型,失败时返回NULL,不会中断整个查询。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.12 00:41:00