sql - 在 SQL Server 中生成字母数字序列
问题描述
我正在使用 SQL Server 存储过程来生成具有以下模式的 10 位数字序列,其中[CustomerCode]
说“ABC”:
[CustomerCode]0000001
...
[CustomerCode]9999999
[CustomerCode]A000001
...
[CustomerCode]Z999999
[CustomerCode]ZA00001
...
[CustomerCode]ZZ99999
[CustomerCode]ZZA0001
...
[CustomerCode]ZZZZZZZ
所以这个存储过程将一个字符串作为输入参数,并返回下一个值,例如它采用'ABCZ999999'并返回'ABCZA00001'。
我有以下存储过程和函数,但它们不能完全工作,我似乎无法正确处理。
任何帮助表示赞赏。
-- Function to increment numeric value
CREATE FUNCTION [dbo].[IncrementNumericValue]
(@CurrentValue Varchar(2))
RETURNS Varchar(2)
AS
BEGIN
DECLARE @RetValue Varchar(2)
IF (@CurrentValue < CAST(9 AS Varchar(2)))
BEGIN
SET @RetValue = CAST((CAST(@CurrentValue AS Int) + Cast(1 AS Int)) AS Varchar(2))
END
ELSE IF (@CurrentValue >= CAST(9 AS Varchar(2)))
BEGIN
SET @RetValue = CAST(0 AS Varchar(2))
END
ELSE
BEGIN
SET @RetValue = CAST('-' AS Varchar(2))
END
RETURN (@RetValue)
END
-- Function to increment alpha value
CREATE FUNCTION [dbo].[IncrementAlphaValue]
(@CurrentValue Varchar(2))
RETURNS Varchar(2)
AS
BEGIN
DECLARE @RetValue Varchar(2)
IF (@CurrentValue < CAST(9 AS Varchar(2)))
BEGIN
SET @RetValue = CAST((CAST(@CurrentValue AS Int) + CAST(1 AS Int)) AS Varchar(2))
END
ELSE IF (@CurrentValue = CAST(9 AS Varchar(2)))
BEGIN
SET @RetValue = CAST('A' As Varchar(2))
END
ELSE IF ((@CurrentValue >= CAST('A' AS Varchar(2)))
AND (@CurrentValue < CAST('Z' AS Varchar(2))))
BEGIN
SET @RetValue = CAST((Char((CAST(ASCII(@CurrentValue) AS Int) + CAST(1 AS Int)))) AS Varchar(2))
END
ELSE IF (@CurrentValue = CAST('Z' AS Varchar(2)))
BEGIN
SET @RetValue = CAST(0 AS Varchar(2))
END
ELSE
BEGIN
SET @RetValue = CAST('-' AS Varchar(2))
END
RETURN (@RetValue)
END
-- Function to calculate the next sequence of the pattern
CREATE PROCEDURE [dbo].[GetNextSequence]
@NewTarget Varchar(10) OUTPUT
AS
BEGIN
DECLARE @LastVariable Varchar(10)
DECLARE @PositionIndex Int
DECLARE @PassParameterWidth Int
DECLARE @TargetWidth Int
DECLARE @SelectedValue Varchar(2)
DECLARE @NewValue Varchar(2)
DECLARE @FinalValue Varchar(10)
DECLARE @ReplaceStringLength Int
DECLARE @ReplaceString Varchar(10)
DECLARE @NewCODE Varchar(10)
DECLARE @MaxTargetWidth Int
DECLARE @customerCode char(3)
DECLARE @NumberOfNine Int
DECLARE @AlphaNumericPartWidth Int
BEGIN
BEGIN
-- Input
SET @customerCode = 'ABC'
SELECT @LastVariable = 'ABCZ999999'
SET @PassParameterWidth = Len(@LastVariable)
SET @AlphaNumericPartWidth = @PassParameterWidth - Len(@customerCode)
SET @LastVariable = SUBSTRING(@LastVariable, 4, 7)
SET @TargetWidth = Cast(4 AS Int)
SET @MaxTargetWidth = Cast(7 AS Int)
SET @NewValue = ''
SET @FinalValue = ''
SET @ReplaceStringLength = Cast(0 AS Int)
SET @ReplaceString = ''
SET @NumberOfNine = 0
IF (@AlphaNumericPartWidth = CAST(7 AS Int))
BEGIN
SET @PositionIndex = @AlphaNumericPartWidth
WHILE(@PositionIndex > 0)
BEGIN
SET @SelectedValue = SUBSTRING(@LastVariable, @PositionIndex, 1)
IF (@SelectedValue LIKE '[A-Z]') -- Increment alpha
SET @NewValue = dbo.IncrementAlphaValue(@SelectedValue)
ELSE -- Increment numeric
SET @NewValue = dbo.IncrementNumericValue(@SelectedValue)
-- Right most digit
IF (@PositionIndex = 1)
BEGIN
IF (@SelectedValue = 'Z')
BEGIN
-- If left of 'Z' all '9' replace with 'ZA'
IF (LEN(REPLACE(PARSENAME(REPLACE(@LastVariable, 'Z', '.'), 1), '9','')) = 0)
BEGIN
SET @LastVariable = REPLACE(@LastVariable, 'Z', 'ZA');
SET @LastVariable = REPLACE(@LastVariable, '9', '0');
RETURN
END
END
-- If prefixed with letter or All '9', increment alpha
IF (@NewValue LIKE '[A-Y]' OR LEN(REPLACE(@LastVariable, '9','')) = 0)
BEGIN
SET @NewValue = dbo.IncrementAlphaValue(@SelectedValue)
END
END
SET @FinalValue = @NewValue + @FinalValue
-- Break is it's 1
IF (@NewValue <> 9)
BREAK
-- Move position to left
SET @PositionIndex = @PositionIndex - Cast(1 As Int)
END
-- Check Final value length
IF (LEN(@FinalValue) <= @MaxTargetWidth)
BEGIN
SET @LastVariable = @customerCode + @LastVariable
-- Get replace string length
SET @ReplaceStringLength = @PassParameterWidth - Len(@FinalValue)
-- Get replace string
SET @ReplaceString = LEFT(@LastVariable, @ReplaceStringLength)
-- NEW CODE
SET @NewCODE = @ReplaceString + @FinalValue
SET @NewTarget = @NewCODE
END
ELSE
BEGIN
SET @NewTarget = 'ERROR1'
END
END
ELSE
BEGIN
SET @NewTarget = 'ERROR222'
END
END
END
END
解决方案
这样的事情应该可以解决问题:
--declare @test varchar(10) = 'ABCZZ99999';
--declare @test varchar(10) = 'ABC0000001';
declare @test varchar(10) = 'ABCZZZZZZG';
--declare @test varchar(10) = 'ABC9999999';
--declare @test varchar(10) = 'ABCA000001';
--declare @test varchar(10) = 'ABCE999999';
--declare @test varchar(10) = 'ABCZ999999';
--declare @test varchar(10) = 'ABCZG99999';
--declare @test varchar(10) = 'ABCZA00001';
--declare @test varchar(10) = 'ABCZZ99999';
declare @idpart varchar(7) = SUBSTRING(@test, 4, 7);
declare @custpart varchar(7) = SUBSTRING(@test, 1, 3);
declare @numpos int = (SELECT PATINDEX('%[0-9]%', @idpart));
declare @numpart varchar(7);
declare @letterpart varchar(7);
if @numpos > 0
BEGIN
SET @numpart = SUBSTRING(@idpart, @numpos, 8 - @numpos);
SET @letterpart = SUBSTRING(@idpart, 1, @numpos - 1);
END
ELSE
BEGIN
SET @numpart = '';
SET @letterpart = @idpart;
END
declare @newnumpart varchar(7);
declare @newletterpart varchar(7);
IF @numpart = ''
BEGIN
SET @newletterpart = (SELECT REPLACE
(REPLACE
(REPLACE
(REPLACE
(REPLACE
(REPLACE
(REPLACE
(REPLACE
(REPLACE
(REPLACE
(REPLACE
(REPLACE
(REPLACE
(REPLACE
(REPLACE
(REPLACE
(REPLACE
(REPLACE
(REPLACE
(REPLACE
(REPLACE
(REPLACE
(REPLACE
(REPLACE
(REPLACE(@letterpart, 'Y', 'Z'),
'X', 'Y'),
'W', 'X'),
'V', 'W'),
'U', 'V'),
'T', 'U'),
'S', 'T'),
'R', 'S'),
'Q', 'R'),
'P', 'Q'),
'O', 'P'),
'N', 'O'),
'M', 'N'),
'L', 'M'),
'K', 'L'),
'J', 'K'),
'I', 'J'),
'H', 'I'),
'G', 'H'),
'F', 'G'),
'E', 'F'),
'D', 'E'),
'C', 'D'),
'B', 'C'),
'A', 'B'));
SET @newnumpart = '';
END
ELSE
BEGIN
declare @non9 int = (SELECT PATINDEX('%[0-8]%', @numpart));
IF @non9 > 0
BEGIN
--Number part is not all 9s so we can cast as int add 1 and cast back to varchar
declare @numint int = (SELECT CAST(@numpart as int) + 1);
declare @numstr varchar(7) = (SELECT CAST(@numint as varchar(7)));
SET @newnumpart = (SELECT REPLICATE('0', LEN(@numpart) - LEN(@numstr)) + @numstr);
SET @newletterpart = @letterpart;
END
ELSE
IF @letterpart = ''
BEGIN
SET @newnumpart = '000001';
SET @newletterpart = 'A';
END
ELSE
BEGIN
declare @nonZ int = (SELECT PATINDEX('%[A-Y]%', @letterpart));
IF @nonZ > 0
BEGIN
SET @newletterpart = (SELECT REPLACE
(REPLACE
(REPLACE
(REPLACE
(REPLACE
(REPLACE
(REPLACE
(REPLACE
(REPLACE
(REPLACE
(REPLACE
(REPLACE
(REPLACE
(REPLACE
(REPLACE
(REPLACE
(REPLACE
(REPLACE
(REPLACE
(REPLACE
(REPLACE
(REPLACE
(REPLACE
(REPLACE
(REPLACE(@letterpart, 'Y', 'Z'),
'X', 'Y'),
'W', 'X'),
'V', 'W'),
'U', 'V'),
'T', 'U'),
'S', 'T'),
'R', 'S'),
'Q', 'R'),
'P', 'Q'),
'O', 'P'),
'N', 'O'),
'M', 'N'),
'L', 'M'),
'K', 'L'),
'J', 'K'),
'I', 'J'),
'H', 'I'),
'G', 'H'),
'F', 'G'),
'E', 'F'),
'D', 'E'),
'C', 'D'),
'B', 'C'),
'A', 'B'));
SET @newnumpart = (SELECT REPLICATE('0', LEN(@numpart) - 1) + '1');
END
ELSE
BEGIN
SET @newletterpart = @letterpart + 'A';
SET @newnumpart = (SELECT REPLICATE('0', LEN(@numpart) - 2) + '1');
END
END
END
SELECT @custpart + @newletterpart + @newnumpart;
显然我只是将它作为一个直接查询来完成,但从中生成一个存储过程是微不足道的。两个关键测试用例是数字元素是否全为 9,字母元素是否全为 Z。如果数字元素不是全 9,那么我们通过强制转换为 int 加 1 并使用REPLICATE
填充零来强制转换回 varchar 来获得下一个数字部分。如果数字元素全为零,则进入第二个关键案例。我们是否有一个可以递增的字母,或者我们是否在末尾添加了一个额外的“A”,因为我们只有 Zs。至少就优雅而言,我通过多个“REPLACE”增加字母 AY 的方式可能会有所改进,但它很快!
不过有一件事让我很困惑。如果这是一个遗留问题,那么以前的开发人员是如何产生下一个价值的。大概他们这样做了?
推荐阅读
- jquery - 如何在jQuery中根据行应用样式
- python - ValueError:具有多个元素的数组的真值不明确。使用 a.any() 或 a.all() 进行图像处理
- c++ - 在 C++ 中从 double 转换为 int
- php - 如何通过 .htaccess 重写 url
- html - 动画 CSS Uncentering Div
- javascript - 发表的评论仅在刷新时呈现在 DOM 中(React)
- javascript - 使用 HTML 和 JS 通过 URL 访问 XML 文件
- java - Kotlin Gradle API 依赖项在消费者中不可用
- apache-flink - Flink 的 hive 流与 iceberg/hudi/delta
- android-studio - Flutter Advance pdf 查看器插件在模拟器中运行良好,但在真实设备中显示错误