【问题标题】:Extract Text from string starting from the righ no substring. SQL从现在的子字符串开始从字符串中提取文本。 SQL
【发布时间】:2017-04-28 18:25:58
【问题描述】:

我有一列包含变量名称,例如

UB121216SVC0054
12122016TH10076
UB121216OH10058

我想提取从右边开始的字母。

SVC
TH
OH

由于字母和数字的数量不同,我不能使用子字符串来指定第一个和最后一个字符。

我该怎么办?

【问题讨论】:

  • 你能说得更具体点吗?
  • 确切的模式是什么?是number/character .. SVC .. numbers吗?它们总是以数字结尾吗?
  • 它总是以数字结尾,用反向和标准查找字母 +2 做一些事情?
  • 你说“字母和数字的数量不同”。不清楚您的示例中哪些字母和数字有所不同。
  • 字母的数量可以在开头,但我只看中间的字母。

标签: sql sql-server sql-server-2012


【解决方案1】:

这将适用于您的所有测试用例... 它最初修剪所有尾随数字,然后仅对前面的字符进行子字符串处理,直到找到一个数字。将@var 更改为您的任何测试用例。

declare @var varchar(50) = ' '

select case when @var is not null and @var <> '' then 
      right(reverse(substring(reverse(@var),PATINDEX('%[^0-9]%',reverse(@var)),len(@var) - PATINDEX('%[^0-9]%',reverse(@var)))),PATINDEX('%[0-9]%',reverse(reverse(substring(reverse(@var),PATINDEX('%[^0-9]%',reverse(@var)),len(@var) - PATINDEX('%[^0-9]%',reverse(@var)))))) - 1)
      else null end

编辑

declare @var varchar(50) = 'claim_ud   H4748sd115600'

select case 
      when @var is not null and @var <> '' then
            case 
                when  PATINDEX('% %',@var) = 0 then
                right(reverse(substring(reverse(@var),PATINDEX('%[^0-9]%',reverse(@var)),len(@var) - PATINDEX('%[^0-9]%',reverse(@var)))),PATINDEX('%[0-9]%',reverse(reverse(substring(reverse(@var),PATINDEX('%[^0-9]%',reverse(@var)),len(@var) - PATINDEX('%[^0-9]%',reverse(@var)))))) - 1)
                else
                right(reverse(substring(reverse(stuff(@var,PATINDEX('% %',@var),PATINDEX('% %',reverse(@var)) - PATINDEX('% %',@var),1)),PATINDEX('%[^0-9]%',reverse(stuff(@var,PATINDEX('% %',@var),PATINDEX('% %',reverse(@var)) - PATINDEX('% %',@var),1))),len(stuff(@var,PATINDEX('% %',@var),PATINDEX('% %',reverse(@var)) - PATINDEX('% %',@var),1)) - PATINDEX('%[^0-9]%',reverse(stuff(@var,PATINDEX('% %',@var),PATINDEX('% %',reverse(@var)) - PATINDEX('% %',@var),1))))),PATINDEX('%[0-9]%',reverse(reverse(substring(reverse(stuff(@var,PATINDEX('% %',@var),PATINDEX('% %',reverse(@var)) - PATINDEX('% %',@var),1)),PATINDEX('%[^0-9]%',reverse(stuff(@var,PATINDEX('% %',@var),PATINDEX('% %',reverse(@var)) - PATINDEX('% %',@var),1))),len(stuff(@var,PATINDEX('% %',@var),PATINDEX('% %',reverse(@var)) - PATINDEX('% %',@var),1)) - PATINDEX('%[^0-9]%',reverse(stuff(@var,PATINDEX('% %',@var),PATINDEX('% %',reverse(@var)) - PATINDEX('% %',@var),1))))))) - 1)
                end
      else null end

【讨论】:

  • 消息 536 的相同概率,级别 16,状态 2,行 3 传递给 RIGHT 函数的长度参数无效。
  • 你尝试将什么传递给 var @gizq?
  • @gizq 如果"中间没有任何字母,例如 UH234534254325,就会发生这种情况
  • 总有一个中间值,是创建行的人的首字母,可能是因为我有空值?
  • @gizq 我把它包装在一个盒子里来处理 null 或空白
【解决方案2】:

对于您提供的示例,以下代码似乎是一个足够简单的解决方案:

select (case when substring(col, 11, 1) between '0' and '9'
             then substring(col, 9, 2)
             else substring(col, 9, 3)
        end)

这是假设代码是 2 个或 3 个字符并且总是从第 9 个位置开始。

【讨论】:

  • 它工作正常,但子字符串并不总是从 pos 9 开始
【解决方案3】:

请注意,此版本创建的基本执行计划与 Radu 的代码(上图)相同,但我发现它更具可读性。包括评论。

-- Create a testing table
CREATE TABLE #codes (code varchar(32))
GO
INSERT INTO #codes Values ('UB121216SVC0054')
INSERT INTO #codes Values ('12122016TH10076')
INSERT INTO #codes Values ('UB121216OH10058')
GO
-- Get the substring data
SELECT   -- Get the data up to the first non-letter
    Reverse(LEFT(fragment, patindex('%[^A-Za-z]%', fragment)-1)) as substr
FROM (  -- trim the field at the first letter
    SELECT SUBSTRING(rcode, patindex('%[A-Za-z]%', rcode), len(rcode)) as fragment
    FROM (  -- Working with the reversed values
        SELECT reverse(code) as rcode 
        FROM #codes
        ) as ReverseTable
    ) as WorkTable

【讨论】:

  • 注意:我用一个包含额外字段和 90k+ 行的表进行了测试,即使返回额外的字段,计划和执行时间都是一样的。
猜你喜欢
  • 1970-01-01
  • 2019-02-08
  • 1970-01-01
  • 1970-01-01
  • 2011-07-21
  • 1970-01-01
  • 1970-01-01
  • 2023-03-25
相关资源
最近更新 更多