【问题标题】:invalid length parameter passed to the left or substring function - Error is not happening consistently for the same data传递给左函数或子字符串函数的长度参数无效 - 相同数据的错误不会始终如一地发生
【发布时间】:2021-07-19 07:30:00
【问题描述】:

我收到了错误

传递给左侧或子字符串函数的长度参数无效

我知道传递了负值,这是错误的原因。

子字符串查询是获取第一个破折号和第二个破折号之间的数据

例如:样本数据“ABC-123-ABCDEF”,预期结果“123”

对于相同的数据,错误不会始终如一地发生,有时会发生错误,并且大多数时候都可以正常工作。我想了解为什么查询对于相同的数据表现不同。

SELECT 
    item.tril_gid,
    CAST(SUBSTRING(comp.fr_productnumber,
            CHARINDEX('-', comp.fr_productnumber, 1) + 1,
                 CHARINDEX('-', comp.fr_productnumber,
            CHARINDEX('-', comp.fr_productnumber, 1) + 1) -
                 CHARINDEX('-', comp.fr_productnumber, 1) - 1) AS INT) AS comp.ProNum
FROM   
    SCQLI comp WITH(nolock)
LEFT JOIN 
    ffc ffc WITH(nolock) ON ffc.sc_quote_line_item = comp.tril_gid
LEFT JOIN 
    ffa ffa WITH(nolock) ON ffa.tril_gid = ffc.ffassembly
LEFT JOIN 
    scq item WITH(nolock) ON item.tril_gid = ffa.sc_quote_line_item
INNER JOIN 
    jde jde WITH(nolock) ON jde.tril_gid = item.fr_jde_order
INNER JOIN 
    frq frq WITH(nolock) ON frq.tril_gid = jde.frquoterevision
WHERE  
    comp.fr_jde_order = 'QFXZZBSHH1YRFZULBEBS3C4HULDV42VR' 
    AND comp.FR_ProductNumber <> ''

【问题讨论】:

  • 当遇到与您的假设不匹配的值时,您的代码不是为了安全地忽略或使用涉及子字符串的表达式中的替代逻辑而编写的。更重要的是,不要再用nolock 乱写代码了。此外,由于连接顺序以及内连接和外连接的混合,您的左连接会隐式转换为内连接。

标签: sql-server substring


【解决方案1】:

我会仔细检查导致错误的数据,当我运行以下查询时,我会得到预期的结果。您的 fr_productnumber 可能无效(缺少“-”或其他内容)。你有其他样品可以提供吗?见下例:

select 
     comp.fr_productnumber
    ,Cast(Substring(comp.fr_productnumber,
            Charindex('-', comp.fr_productnumber, 1) + 1,
                 Charindex('-', comp.fr_productnumber,
            Charindex('-', comp.fr_productnumber, 1) + 1) -
                 Charindex('-', comp.fr_productnumber, 1) - 1) AS INT) as [Result]
from
(
    select 'ABC-123-ABCDEF' as fr_productnumber
) as comp

产生:

| fr_productnumber | Result |
| ---------------- | ------ |
|  ABC-123-ABCDEF  |  123   |

【讨论】:

    【解决方案2】:

    以下说明了两种不同的方法。第一个是ParseName() ...前提是您的数据不超过4个元素,第二个使用一点JSON

    示例

    Declare @YourTable Table ([SomeCol] varchar(50))  
    Insert Into @YourTable Values 
     ('ABC-123-ABCDEF')
    
    Select SomeCol
          ,WithParseName = parsename(replace(SomeCol,'-','.'),2)
          ,WithJSON      = JSON_VALUE('["'+replace(SomeCol,'-','","')+'"]','$[1]')
     From @YourTable
    

    退货

    SomeCol         WithParseName   WithJSON
    ABC-123-ABCDEF  123             123
    

    【讨论】:

      【解决方案3】:

      首先,在 SQL Server 中进行字符串操作时应该记住两件事:

      • 您应该使用CROSS APPLY 保存一个计算并将其输入下一个计算。这样可以省去很多重复,很好的利用了 DRY 原则。
      • CHARINDEX 可以在找不到字符串的情况下返回 0,因此为了安全起见,需要将其设为空。

      其他人提到的其他点:

      • NOLOCK 应该避免,除非您真的知道自己在做什么,并且乐于得到错误的结果。
      • 你的一些LEFT JOINs 没有意义,应该是INNER JOIN

      您的查询现在变为:

      SELECT 
          item.tril_gid,
          TRY_CAST(SUBSTRING(comp.fr_productnumber,
                  v1.firstDash + 1,
                       v2.SecondDash - v1.firstDash - 1
              ) AS INT) AS comp.ProNum
      FROM   
          SCQLI comp
      INNER JOIN 
          ffc ffc ON ffc.sc_quote_line_item = comp.tril_gid
      INNER JOIN 
          ffa ffa ON ffa.tril_gid = ffc.ffassembly
      INNER JOIN 
          scq item ON item.tril_gid = ffa.sc_quote_line_item
      INNER JOIN 
          jde jde ON jde.tril_gid = item.fr_jde_order
      INNER JOIN 
          frq frq ON frq.tril_gid = jde.frquoterevision
      CROSS APPLY (VALUES(
          NULLIF(CHARINDEX('-', comp.fr_productnumber, 1), 0)
      ) ) v1(firstDash)
      CROSS APPLY (VALUES(
          NULLIF(CHARINDEX('-', comp.fr_productnumber, v1.firstDash + 1), 0)
      ) ) v2(secondDash)
      WHERE  
          comp.fr_jde_order = 'QFXZZBSHH1YRFZULBEBS3C4HULDV42VR' 
          AND comp.FR_ProductNumber <> ''
      

      为什么您的查询只在某些时候有效,即使是在相同的数据上?

      这个问题的答案可能在于我们看不到的部分查询计划,即在什么时候计算字符串函数? (请注意,Compute Scalar 在计划中的位置并没有告诉您这一点。)

      如果它们是在过滤发生之前计算的,那么如果不应该出现在结果中的行导致错误,则查询可能会失败。无法保证服务器会做什么,因此您必须添加额外的检查。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2016-06-09
        • 1970-01-01
        • 2014-03-01
        • 2019-08-30
        相关资源
        最近更新 更多