子字符串 SQL 错误传递给 SUBSTRING 的长度参数无效

问题描述 投票:0回答:1

我有以下 5 个字符串,我正在尝试解析它们,例如:

1. Person is (Christopher Bowles known as Chris)
2. This is a test entry
3. Identified as Jonathan Sykes known as John)
4. Registered as (Patrick Joseph known as Pat) (Or also Patty)
5. Guy called as Richard Smith known as Rich) (Or also Richie)

我的查询如下:

SELECT DisplayName = LTRIM(RTRIM(SUBSTRING(n.name, CHARINDEX('(', n.name) + 1, (CHARINDEX('known as', n.name) - CHARINDEX('(', n.name)) - 1)))
FROM #nameTest n
WHERE 1 = 1
AND n.name LIKE '%known as%'

在第五个字符串上失败并出现以下错误:

传递给 LEFT 或 SUBSTRING 函数的长度参数无效。

这是因为称为出现在''之前。我的问题是,我该如何处理这种情况?任何想法将不胜感激?

要在 Microsoft SQL Server 2022 中重新创建测试数据:

CREATE TABLE #nameTest
(   
    name    NVARCHAR(1024) NOT NULL,
)

INSERT INTO #nameTest(name)
VALUES ('Person is (Christopher Bowles known as Chris)'),
('This is a test entry'),
('Identified as Jonathan Sykes known as John)'),
('Registered as (Patrick Joseph known as Pat) (Or also Patty)'),
('Guy called as Richard Smith known as Rich) (Or also Richie)')

输出应该是:

1. Christopher Bowles
2. Identified as Jonathan Sykes
3. Patrick Joseph
sql sql-server
1个回答
0
投票

让我们稍微解构一下这个问题。对于诸如“无效长度”之类的问题,最好的调试方法是输出进入 SUBSTRING 的部分:

SELECT  CHARINDEX('(', n.name) + 1, CHARINDEX('known as', n.name)
,   CHARINDEX('known as', n.name) - CHARINDEX('(', n.name)
,   *
FROM #nameTest n
WHERE 1 = 1
AND n.name LIKE '%known as%'

输出:

(第 1 栏) (第2栏) (第3栏) 名字
12 31 20 此人是(Christopher Bowles 又名 Chris)
1 30 30 确认为乔纳森·赛克斯(Jonathan Sykes),又名约翰)
16 31 16 注册为(帕特里克·约瑟夫(Patrick Joseph),又名帕特)(或者也称为帕蒂)
45 29 -15 一个叫理查德·史密斯(Richard Smith)的人,也被称为里奇(Rich)(或者也叫里奇)

我们看到有一个值为负数,子字符串不喜欢这样。 有很多方法可以缓解这个问题:

  1. 地点:
select ...
WHERE ...
and CHARINDEX('known as', n.name) > CHARINDEX('(', n.name)
  1. 如果您不喜欢在哪里,您可以在以下情况下进行操作:
SELECT DisplayName = case when CHARINDEX('known as', n.name) > CHARINDEX('(', n.name) then LTRIM(RTRIM(SUBSTRING(n.name, CHARINDEX('(', n.name) + 1, (CHARINDEX('known as', n.name) - CHARINDEX('(', n.name)) - 1))) end
...

这会保留该行,但如果索引的顺序不正确,则将其变为 NULL。

为了简化这一点,我通常创建“变量”,使用 CROSS APPLY 删除一些复制粘贴:

SELECT DisplayName = LTRIM(RTRIM(SUBSTRING(n.name, startParen + 1, startKnownAs - startParen - 1)))
FROM #nameTest n
CROSS APPLY (
        SELECT  CHARINDEX('(', n.name) as startParen
        ,   CHARINDEX('known as', n.name) startKnownAs
    ) x
WHERE 1 = 1
AND n.name LIKE '%known as%'

然后就可以轻松地以您想要的方式应用上述解决方案了:

  1. 地点:
...
WHERE ...
AND startParen < startKnownAs
  1. 案例:
SELECT DisplayName = case when startParen < startKnownAs THEN LTRIM(RTRIM(SUBSTRING(n.name, startParen + 1, startKnownAs - startParen - 1))) END
...
© www.soinside.com 2019 - 2024. All rights reserved.