【问题标题】:Subtraction of CHARINDEX in SUBSTRING is not workingSUBSTRING 中的 CHARINDEX 减法不起作用
【发布时间】:2023-03-10 09:12:01
【问题描述】:

我需要在列名称中分解一个值:AB: ABC-ABCDE 我需要中间部分,即ABC。我正在使用 SUBSTRING 和 CHARINDEX 来完成此操作,但出现错误:

Msg 537, Level 16, State 2, Line 393
Invalid length parameter passed to the LEFT or SUBSTRING function.

当我减去 CHARINDEX 以获得 SUBSTRING 中的最后一个值时,就会发生这种情况。 代码:

SELECT PRODUCT = (SUBSTRING(Name, CHARINDEX(' ',Name)+1,CHARINDEX('-',Name)-(CHARINDEX(' ',Name)+1)))
FROM A

我做错了什么?

更新:表中有另一个值,例如:'ABC-ABC: ABCDEFG-ABCDEF GH'。这给出了负值,因此为什么会出现错误。结果应该是ABCDEFG

【问题讨论】:

  • 表达式导致超出范围的值,因此出现错误。单独评估表达式以查找正在评估的参数值对于字符串是否正确。
  • @Dheerendra 我确实分别评估了它们,我得到了两个值的数字,所以它应该能够减去
  • 如果减法结果是负值怎么办?评估减法并检查
  • 我确实进行了评估,不,它不会导致负值,因为我已经将更大的长度切换到开头。如果不是减法,我还能如何做到这一点?
  • 我偶尔会遇到这种情况,它总是是一个导致负长度的边缘情况。真的很难找到。

标签: sql sql-server tsql substring charindex


【解决方案1】:

另一种选择是使用NullIf()“强制”NULL

示例

... NullIf(CHARINDEX(' ',Name),0) + 1 ...

... NullIf(CHARINDEX('-',Name),0) ...

**

EDIT - 请求更新

**

Declare @YourTable table (Name varchar(50))
Insert Into @YourTable values
( 'AB: ABC-ABCDE')
,('ABC-ABC: ABCDEFG-ABCDEF GH')

Select A.*
      ,ltrim(rtrim(left(substring(Name,charindex(':',Name+':')+1,len(Name))
           ,charindex('-',substring(Name,charindex(':',Name+':')+1,len(Name))+'-') -1
           )))
 From  @YourTable A

退货

Name                          (No column name)
AB: ABC-ABCDE                 ABC
ABC-ABC: ABCDEFG-ABCDEF GH    ABCDEFG

【讨论】:

  • @Stephanie 鉴于更新,您要查找字符串的哪一部分?
  • 分号之后和分号之后的破折号之前。如果值为 'ABC-ABC: ABCDEFG-ABCDEF GH' 那么我想要 'ABCDEFG'
  • @Stephanie 很高兴您能够找到解决方案。总是乐于提供帮助
【解决方案2】:

你没有空间。我发现最简单的方法就是添加一个:

SELECT PRODUCT = (SUBSTRING(Name, CHARINDEX(' ', Name + ' ') + 1, CHARINDEX('-', Name + '-') - (CHARINDEX(' ', Name + ' ') + 1)))
FROM A

我不能 100% 确定这是否符合您的要求,但它会解决您遇到的错误。

【讨论】:

    【解决方案3】:

    你可能会走另一条路:

    DECLARE @mockup TABLE(SomeValue VARCHAR(100));
    INSERT INTO @mockup VALUES('AB: ABC-ABCDE')
                             ,('CD: blah-blub')
                             ,('Wrong Value here')
                             ,('MissingEnd: isCorrect');
    

    --查询将从 XML 中选择第二个元素。

    SELECT CAST('<x>' + REPlACE(REPLACE(m.SomeValue,'-',' '),' ','</x><x>') + '</x>' AS XML).value('/x[2]','nvarchar(max)')
    FROM @mockup m;
    

    诀窍是:使用一些替换将您的 AB: ABC-ABCDE 转换为类似 XML 的

    <x>AB:</x>
    <x>ABC</x>
    <x>ABCDE</x>
    

    从这个 XML 中,我们可以轻松选择第二个元素。

    一个积极的副作用:这种方法更能容忍错误的价值观......

    更新

    你的坏价值观...新技巧是使用STUFF() 将所有内容切掉直到双点:

    DECLARE @mockup TABLE(SomeValue VARCHAR(100));
    INSERT INTO @mockup VALUES('AB: ABC-ABCDE')
                             ,('CD: blah-blub')
                             ,('Wrong Value here')
                             ,('MissingEnd: isCorrect')
                             ,('ABC-ABC: ABCDEFG-ABCDEF GH');
    
    SELECT CAST('<x>' + REPlACE(REPLACE(STUFF(m.SomeValue,1,CHARINDEX(':',m.SomeValue),''),'-',' '),' ','</x><x>') + '</x>' AS XML).value('/x[2]','nvarchar(max)')
    FROM @mockup m;
    

    【讨论】:

      【解决方案4】:

      您的问题无法重现。

      DECLARE @Name varchar(31) = 'AB: ABC-ABCDE';
      
      SELECT SUBSTRING(@Name, CHARINDEX(' ',@Name)+1,CHARINDEX('-',@Name)-(CHARINDEX(' ',@Name)+1))
      

      ABC 中的结果。

      您的表格中可能有一些数据不符合您声称的格式。

      【讨论】:

      • 你是对的,我可能有另一个值,它给出了一个负值来减去。还有什么我可以用来实现这一目标的吗?不知道如何处理负面影响。
      • 你应该怎么做取决于不合格数据采取什么形式,遇到它时你想得到什么结果。在我提供任何具体建议之前,您需要将其添加到您的问题中。如果你想要 NULL,你可以使用 John 的答案,如果你想要连字符之前的所有内容,你可以使用 Gordon 的答案。
      • 我自己也真的不明白。我确实仔细评估了数据。我分别做了减法,看看是否有任何负值,但我没有看到类似的东西。当我对单个行进行过滤时它可以工作,但是当我对整个表格进行过滤时,它就不起作用了。感谢您的帮助,如果我发现了什么,我会更新您
      • 我发现了问题,值的第一部分有一个破折号,例如:'ABC-ABC: ABCDEFG-ABCDEF GH'
      【解决方案5】:

      有时会有一些您不希望出现的空间。
      所以得到从":""-"的子串并修剪它:

      RTRIM(LTRIM(SUBSTRING(Name, CHARINDEX(':',Name)+1,CHARINDEX('-',Name)-(CHARINDEX(':',Name)+1))))
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2012-11-15
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2012-02-24
        • 2013-05-29
        • 2021-11-29
        相关资源
        最近更新 更多