【问题标题】:sql extract rightmost number in string and incrementsql提取字符串中最右边的数字并递增
【发布时间】:2020-02-04 16:21:49
【问题描述】:

我有类似的交易代码

 "A0004", "1B2005","20CCCCCCC21"

我需要提取最右边的数字并将交易代码加一

"AA0004"----->"AA0005"
"1B2005"------->"1B2006"
"20CCCCCCCC21"------>"20CCCCCCCC22"

在 SQL Server 2012 中。

  • 字符串长度未知
  • right(n?) 总是编号

处理不重要的字符串和数字长度超出了我的范围。 总是缺少一些逻辑。

LEFT(@a,2)+RIGHT('000'+CONVERT(NVARCHAR,CONVERT(INT,SUBSTRING( SUBSTRING(@a,2,4),2,3))+1)),3

【问题讨论】:

  • 另一个很好的例子,为什么你不应该在同一列中组合不同类型的信息
  • SELECT REVERSE(LEFT(REVERSE('20CCCCCCCC12345'), PATINDEX('%[^0-9]%', REVERSE('20CCCCCCCC12345')) - 1))。现在你知道为什么你永远不想在 T-SQL 中进行字符串操作了。增加它作为一个数字 并将其返回原始位数留给读者作为练习(这也不是野餐)。如果可能的话,在插入到自己的列中时提取这些数据。痛苦只有一次,然后你就会永远受益。

标签: sql sql-server string tsql increment


【解决方案1】:

首先,我想明确一点:我完全同意 cmets 对 a_horse_with_no_name 和 Jeroen Mostert 的问题的看法。
您应该每列存储一个数据点,周期。

话虽如此,但我确实意识到很多时候数据库结构无法更改 - 所以这里有一种可能的方法来为您进行计算。

首先,创建并填充示例表(在您以后的问题中保存我们这一步):

DECLARE @T AS TABLE 
(
    col varchar(100)
);

INSERT INTO @T (col) VALUES
('A0004'),
('1B2005'),
('1B2000'),
('1B00'),
('20CCCCCCC21');

(我添加了几个字符串作为你在问题中没有提到的边缘情况)

然后,使用几个cross apply 来最大程度地减少代码重复,我想出了:

SELECT  col,
        LEFT(col, LEN(col) - LastCharIndex + 1) + 
        REPLICATE('0', LEN(NumberString) - LEN(CAST(NumberString as int))) + 
        CAST((CAST(NumberString as int) + 1) as varchar(100)) As Result
FROM @T
CROSS APPLY
(
    SELECT PATINDEX('%[^0-9]%', Reverse(col)) As LastCharIndex
) As Idx
CROSS APPLY 
(
    SELECT RIGHT(col, LastCharIndex - 1) As NumberString
) As NS

结果:

col         Result
A0004       A0005
1B2005      1B2006
1B2000      1B2001
1B00        1B01
20CCCCCCC21 20CCCCCCC22

LastCharIndex 表示字符串中最后一个非数字字符的索引。 NumberString 表示要递增的数字,作为字符串(如果存在,则保留前导零)。

从那里,它只是取字符串的左边部分(即直到数字),并将其连接到新计算的数字字符串,使用Replicate 用确切的数字填充加法结果原始数字字符串的前导零。

【讨论】:

  • 值得注意的是,这会将20CCCCCCC99 变成20CCCCCCC100。这可以说是这段代码可以做的最好的事情,但可能不是预期的。当与 T-SQL 截断字符串的渴望结合在一起时,这会变得特别有害——在进一步处理时,它可能会无意中以 20CCCCCCC10 结束。
  • @ZoharPeled 谢谢。它有效。解决方案对我来说太复杂了。你能帮我把它创建成一个sql函数吗?输入“A0004”输出到“A0005”等等......
【解决方案2】:

试试这个

DECLARE @test nvarchar(1000) ='"A0004", "1B2005","20CCCCCCC21"'
DECLARE @Temp AS TABLE (ID INT IDENTITY,Data nvarchar(1000))
INSERT INTO @Temp 
SELECT @test

;WITH CTE
AS
(
SELECT Id,LTRIM(RTRIM((REPLACE(Split.a.value('.' ,' nvarchar(max)'),'"',''))))  AS Data
,RIGHT(LTRIM(RTRIM((REPLACE(Split.a.value('.' ,' nvarchar(max)'),'"','')))),1)+1 AS ReqData
FROM
(
SELECT ID,
CAST ('<S>'+REPLACE(Data,',','</S><S>')+'</S>' AS XML) AS Data
FROM @Temp
) AS A
CROSS APPLY Data.nodes ('S') AS Split(a)
)
SELECT CONCAT('"'+Data+'"','-------->','"'+CONCAT(LEFT(Data,LEN(Data)-1),CAST(ReqData AS VARCHAR))+'"') AS ExpectedResult
FROM CTE

结果

ExpectedResult
-----------------
"A0004"-------->"A0005"
"1B2005"-------->"1B2006"
"20CCCCCCC21"-------->"20CCCCCCC22"

【讨论】:

  • 在任何以 9 结尾的字符串上都失败。
【解决方案3】:

东西(@X ,LEN(@X)-CASE PATINDEX('%[AZ]%',REVERSE(@X)) WHEN 0 THEN LEN(@X) ELSE PATINDEX('%[AZ]%',REVERSE(@X))- 1 结束+1 ,LEN(((RIGHT(@X,CASE PATINDEX('%[AZ]%',REVERSE(@X)) WHEN 0 THEN LEN(@X) ELSE PATINDEX('%[AZ]%',REVERSE(@X) ))-1 END)/@N)+1)@N) ,((RIGHT(@X,CASE PATINDEX('%[AZ]%',REVERSE(@X)) WHEN 0 THEN LEN(@X) ELSE PATINDEX('%[AZ]%',REVERSE(@X)) -1 END)/@N)+1)@N)

  • 仅适用于数字字符串
  • 99变成100
  • mod(@N) 增量

【讨论】:

    猜你喜欢
    • 2010-12-15
    • 2012-01-24
    • 2018-04-21
    • 2015-02-01
    • 2015-05-19
    • 2022-11-16
    • 1970-01-01
    • 1970-01-01
    • 2023-02-25
    相关资源
    最近更新 更多