我在SQL Server获取下一个编码字符实现的博文中,虽然实现了这个问题,但是感觉维护起来比较麻烦,例如如果调整编码字符串的固定长度,就需要变更三个函数,这样的为何成本确实比较大。面向对象编程很重视讲究开放封闭原则,我认为数据库对象特别函数、存储等对象也要尽量封装成实现单一功能,维护起来简单,也方便后续人员的维护,便利别人也是便利自己。
 
    针对编码字符串的规则,继续延伸总结如下:
1、第一个字符必须是字母A-Z中任意一个字符,其长度可以为1位、2位、3位,……,6位、7位、8位、……;
2、编码字符串满足递进增加。如果编码字符串长度为5位,则编码字符串是A0000,下一个是A0001,直到A9999,其下一个是B0000,直到B9999,其下一个是C0000,……,如果编码是ZB999,下一个是ZC000,……,直到ZZZZZ;无论其长度为1位到N位中的任何一个长度,均要满足递进增加。
 
    我的实现方案是将编码字符串中每一位的字符对应的整数值加工转换为一个10进制整数值,再实现将一个将整数值转换为一个编码字符串,也就是将编码字符串和整数值相互转换。由于方案中是使用了POWER函数,受限其结果值的长度,此方案最多支持8位长度的编码字符串和整数值间的相互转换。
    
    通过以上规则分析,不同长度的编码字符均对应不同的最小和最大编码字符串,我的方案是编码字符串和整数相互转换,也就是不同长度的编码字符对应的不同的相对应的最小和最大整数值,也就是不同的长度对应的不同的整数范围,且这些不同长度对应的整数范围之间是不连续,比如长度1位对应的最大整数值和长度2位对应的最小整数不是相等。
    
    方案的具体实现思路如下:
1、由于使用到数字0-9和字母[A-Z](大写)字母这两类字符,将以上字符和10进制整数值之间的硬编码对应,将其封装为一个表值函数。
2、实现将一个编码字符串转换为一个整数值,此功能封装为一个标量函数。
3、针对不同长度的编码字符串对应的不同最小和最大整数,这个功能也可以检查一个整数值是否在满足转换为一个编码字符串,也封装为一个表值函数。
4、将一个整数值转换为一个编码字符串,此功能也封装在一个标量函数中。
    
    针对上实现方案主要重构的部分包括函数命名,针对表(表值或内联表)函数和标量函数尽量通过命名标识符来区分。还解决了编码字符串穿不同长度的实现来强制修改所涉及三个函数的缺陷。为了讲解方便,我根据该方案的实现思路的4个步骤,将其对应的部分分为:字符映射表值函数、获取编码字符串整数值标量函数、获取编码字符串长度和整数值范围表函数和获取整数值对应的编码字符串变量函数。
 
字符映射表值函数
 
该函数的T-SQL代码如下:
 IF OBJECT_ID(N'dbo.ufn_GetCharTable', 'TF') IS NOT NULL
BEGIN
DROP FUNCTION dbo.ufn_GetCharTable;
END
GO --==================================
-- 功能: 获取字符映射表表值函数
-- 说明: 编码字符只包含0-9和A-Z这两类字符
-- 将以上字符映射到对应十进制数值。
-- 作者: XXX
-- 创建: yyyy-MM-dd
-- 修改: yyyy-MM-dd XXX 修改内容描述
-- 调用: SELECT CodeChar, CodeValue FROM dbo.ufn_GetCharTable();
--==================================
CREATE FUNCTION dbo.ufn_GetCharTable
(
) RETURNS @tblChar TABLE (
[Char] CHAR() NOT NULL,
Value TINYINT NOT NULL
)
--$Encode$--
AS
BEGIN
DECLARE
@intStartIndexID AS TINYINT,
@intEndIndexID AS TINYINT; SELECT
@intStartIndexID = ,
@intEndIndexID = ; -- 初始化0-9数字字符
SELECT
@intStartIndexID = ASCII(''),
@intEndIndexID = ASCII('');
WHILE @intStartIndexID <= @intEndIndexID
BEGIN
INSERT INTO @tblChar ([Char], Value)
VALUES (CHAR(@intStartIndexID), ); SET @intStartIndexID = @intStartIndexID + ;
END -- 初始化A-Z字母字符
SELECT
@intStartIndexID = ASCII('A'),
@intEndIndexID = ASCII('Z');
WHILE @intStartIndexID <= @intEndIndexID
BEGIN
INSERT INTO @tblChar ([Char], Value)
VALUES (CHAR(@intStartIndexID), ); SET @intStartIndexID = @intStartIndexID + ;
END -- 修改每个字符对应的10进制整数值
;WITH tCodeData AS (
SELECT [Char], ROW_NUMBER() OVER (ORDER BY [Char] ASC) AS RowNum
FROM @tblChar
) UPDATE T2
SET T2.Value = T.RowNum -
FROM tCodeData AS T
INNER JOIN @tblChar AS T2
ON T.[Char] = T2.[Char]; RETURN;
END
GO
获取编码字符串整数值标量函数
该函数的T-SQL代码如下:
 IF OBJECT_ID(N'dbo.ufn_GetCodeCharsValue', 'FN') IS NOT NULL
BEGIN
DROP FUNCTION dbo.ufn_GetCodeCharsValue;
END
GO --==================================
-- 功能: 获取编码字符串对应的10进制整数数值
-- 说明: 具体实现阐述
-- 作者: XXX
-- 创建: yyyy-MM-dd
-- 修改: yyyy-MM-dd XXX 修改内容描述
-- 调用: SELECT dbo.ufn_GetCodeIntegerValue('A0000')
--==================================
CREATE FUNCTION dbo.ufn_GetCodeCharsValue
(
@chvCodeChars VARCHAR() -- 编码字符串 ) RETURNS INT
--$Encode$--
AS
BEGIN
SET @chvCodeChars = ISNULL(@chvCodeChars, '');
SET @chvCodeChars = UPPER(@chvCodeChars); DECLARE @intCodeCharsValue AS BIGINT;
SET @intCodeCharsValue = ; DECLARE @tintLength AS TINYINT;
SET @tintLength = LEN(@chvCodeChars); IF @tintLength =
BEGIN
RETURN @intCodeCharsValue;
END DECLARE @tblChar TABLE(
[Char] CHAR() NOT NULL,
Value TINYINT NOT NULL
); INSERT INTO @tblChar ([Char], Value)
SELECT [Char], Value
FROM dbo.ufn_GetCharTable(); -- 编码字符串的首字母必须是A-Z字母字符的逻辑检查
IF NOT EXISTS (SELECT FROM @tblChar WHERE [Char] = SUBSTRING(@chvCodeChars, , ) AND Value >= )
BEGIN
RETURN @intCodeCharsValue;
END WHILE @tintLength >=
BEGIN
SELECT @intCodeCharsValue = @intCodeCharsValue + CAST(Value * POWER(, @tintLength - ) AS BIGINT)
FROM @tblChar
WHERE [Char] = SUBSTRING(@chvCodeChars, , ); SET @chvCodeChars = STUFF(@chvCodeChars, , , ''); SET @tintLength = @tintLength - ;
END RETURN @intCodeCharsValue;
END
GO

获取编码字符串长度和整数值范围表函数

该函数的T-SQL代码如下:
 IF OBJECT_ID(N'dbo.ufn_GetCodeCharsValueTable', 'TF') IS NOT NULL
BEGIN
DROP FUNCTION dbo.ufn_GetCodeCharsValueTable;
END
GO --==================================
-- 功能: 获取编码字符串不同长度对应的整数值范围
-- 说明: 具体实现阐述
-- 作者: XXX
-- 创建: yyyy-MM-dd
-- 修改: yyyy-MM-dd XXX 修改内容描述
-- 调用: SELECT StartValue, EndValue, FixLength FROM dbo.ufn_GetCodeCharsValueTable();
--==================================
CREATE FUNCTION dbo.ufn_GetCodeCharsValueTable
( ) RETURNS @tblCodeCharValue TABLE (
StartValue INT NOT NULL,
EndValue INT NOT NULL,
FixLength TINYINT NOT NULL
)
AS
BEGIN
DECLARE
@tintLength AS TINYINT,
@tintMaxLength AS TINYINT;
SELECT
@tintLength = ,
@tintMaxLength = ; WHILE @tintLength <= @tintMaxLength
BEGIN
INSERT INTO @tblCodeCharValue (StartValue, EndValue, FixLength)
VALUES (dbo.ufn_GetCodeCharsValue(CONCAT('A', REPLICATE('', @tintLength - ))), dbo.ufn_GetCodeCharsValue(CONCAT('Z', REPLICATE('Z', @tintLength - ))), @tintLength); SET @tintLength = @tintLength + ;
END RETURN;
END
GO
获取整数值对应的编码字符串变量函数。
该函数的T-SQL代码如下:
 IF OBJECT_ID(N'dbo.ufn_GetCodeChars', 'FN') IS NOT NULL
BEGIN
DROP FUNCTION dbo.ufn_GetCodeChars;
END
GO --==================================
-- 功能: 获取一个整数值对应的编码字符串
-- 说明: 具体实现阐述
-- 作者: XXX
-- 创建: yyyy-MM-dd
-- 修改: yyyy-MM-dd XXX 修改内容描述
--==================================
CREATE FUNCTION dbo.ufn_GetCodeChars
(
@intCodeCharsValue INT -- 编码字符串整数值
) RETURNS VARCHAR()
--$Encode$--
AS
BEGIN
SET @intCodeCharsValue = ISNULL(@intCodeCharsValue, );
DECLARE @chvCodeChars AS VARCHAR();
SET @chvCodeChars = ''; -- 整数值长度变量
DECLARE @tintFixLength AS TINYINT;
SET @tintFixLength = ; SELECT @tintFixLength = FixLength
FROM dbo.ufn_GetCodeCharsValueTable()
WHERE @intCodeCharsValue BETWEEN StartValue AND EndValue; -- 整数值范围的逻辑检查
IF @tintFixLength =
BEGIN
RETURN @chvCodeChars;
END DECLARE @tblChar TABLE(
[Char] CHAR() NOT NULL,
Value TINYINT NOT NULL
); INSERT INTO @tblChar ([Char], Value)
SELECT [Char], Value
FROM dbo.ufn_GetCharTable(); DECLARE @tintPerCodeValue TINYINT;
SET @tintPerCodeValue = ; WHILE @tintFixLength >=
BEGIN
SET @tintPerCodeValue = @intCodeCharsValue / POWER(, @tintFixLength - ); SELECT TOP @chvCodeChars = @chvCodeChars + [Char], @tintPerCodeValue = Value
FROM @tblChar
WHERE Value <= @tintPerCodeValue
ORDER BY Value DESC; SET @intCodeCharsValue = @intCodeCharsValue - @tintPerCodeValue * POWER(, @tintFixLength - ); SET @tintFixLength = @tintFixLength - ;
END RETURN @chvCodeChars;
END
GO
测试实现效果
 
测试T-SQL代码如下:
 DECLARE @chvCodeChars AS VARCHAR();
SET @chvCodeChars = CONCAT('A', REPLICATE('', - ));
DECLARE @intCodeCharsValue AS INT;
SET @intCodeCharsValue = dbo.ufn_GetCodeCharsValue(@chvCodeChars); SELECT @chvCodeChars AS CurrentCodeChars, @intCodeCharsValue AS CurrentCodeCharsValue, dbo.ufn_GetCodeChars(@intCodeCharsValue + ) AS NextCodeChars
GO
执行后的查询结果如下:
 
博友如有其他更好的解决方案,也请不吝赐教,万分感谢。

SQL Server获取下一个编码字符实现继续重构与增强的更多相关文章

  1. SQL Server获取下一个编码字符实现

    周末看到SQL Server 大V潇湘隐者的获取下一个编码字符串问题,本来作为以上博文的回复,也许回复内容长度超过其允许限制,无法提交.鉴于此,特记录SQL Server实现过程,方便自己回顾和查阅. ...

  2. SQL Server获取下一个编码字符串的实现方案分割和进位

        我在前一种解决方案SQL Server获取下一个编码字符实现和后一种解决方案SQL Server获取下一个编码字符实现继续重构与增强两篇博文中均提供了一种解决编码的方案,考虑良久对比以上两种方 ...

  3. 【转】sql server 获取每一个类别中值最大的一条数据

    /* 数据如下: name val memo a 2 a2(a的第二个值) a 1 a1--a的第一个值 a 3 a3:a的第三个值 b 1 b1--b的第一个值 b 3 b3:b的第三个值 b 2 ...

  4. sql server 获取每一个类别中值最大的一条数据

    /* 数据如下: name val memo a 2 a2(a的第二个值) a 1 a1--a的第一个值 a 3 a3:a的第三个值 b 1 b1--b的第一个值 b 3 b3:b的第三个值 b 2 ...

  5. 第1/24周 SQL Server 如何执行一个查询

    大家好,欢迎来到第1周的SQL Server性能调优培训.在我们进入SQL Server性能调优里枯燥难懂的细节内容之前,我想通过讲解SQL Server如何执行一个查询来建立基础.这个部分非常重要, ...

  6. 第1周 SQL Server 如何执行一个查询

    原文:第1周 SQL Server 如何执行一个查询 大家好,欢迎来到第1周的SQL Server性能调优培训.在我们进入SQL Server性能调优里枯燥难懂的细节内容之前,我想通过讲解SQL Se ...

  7. SQL Server 2008下日志清理方法 2

    SQL Server 2008下日志清理方法 (2011-07-14 10:30:45) 转自 http://blog.sina.com.cn/s/blog_4bdd3d0b0100wfvq.html ...

  8. SQL Server获取索引创建时间&重建时间&重组时间

    之前写过一篇博客"SQL Server中是否可以准确获取最后一次索引重建的时间?",里面主要讲述了三个问题:我们能否找到索引的创建时间?最后一次索引重建(Index Rebuild ...

  9. SQLServer数据库之SQL Server 获取本周,本月,本年等时间内记录

    本文主要向大家介绍了SQLServer数据库之SQL Server 获取本周,本月,本年等时间内记录,通过具体的内容向大家展现,希望对大家学习SQLServer数据库有所帮助. datediff(we ...

随机推荐

  1. STC12C5A60S2笔记3(I/O 端口)

    1. 基本特性 STC 单片机IO口可由软件配置成四种工作模式: 1)准双向口:标准51单片机模式,可用作输入和输出 2) 推挽输入输出:需要更大的驱动电流,当高电平时,拉电流20mA.当低电平时,灌 ...

  2. 记一次Url重写_发布之后iis 404

    把api封装完,客户要求app的url能不能不变(客户之前用的php的api开发app,已经开发了很多了,所以希望不改动url).但是这个规则要求是:xx/api.php?s=/{controller ...

  3. 【译】Activitys, Threads和 内存泄露

    Android编程中一个共同的困难就是协调Activity的生命周期和长时间运行的任务(task),并且要避免可能的内存泄露.思考下面Activity的代码,在它启动的时候开启一个线程并循环执行任务. ...

  4. [nRF51822] 3、 新年也来个总结——图解nRF51 SDK中的Button handling library和FIFO library

    :本篇是我翻译并加入自己理解的nRF51 SDK中按钮相关操作的库和先进先出队列库.虽然是nRF51的SDK,但是通过此文你将更多地了解到在BSP(板级支持)上层嵌入式程序或OS的构建方法. 1.按钮 ...

  5. querySelector和querySelectorAll

    jQuery被开发者如此的青睐和它强大的选择器有很大关系,比起笨重的document.getElementById.document.getElementByName… ,查找元素很方便,其实W3C中 ...

  6. 【重要更新】Senparc.Weixin SDK v4.4 升级说明

    本次更新同时影响以下所有Senparc.Weixin相关版本的dll: Senparc.Weixin.dll 升级到 v4.4.2(重要) Senparc.Weixin.MP.dll 升级到 v13. ...

  7. Node.js与Sails~日志机制log

    回到目录 看到Sails的日志就会想起来log4net,确实它们在很多地方是相似的,都是采用分级别记录的方式,而sails我觉得在使用上更加方便,它不需要我们做多于的事情,直接sails.log.级别 ...

  8. iOS-国家气象局-天气预报接口等常用接口

    接口地址: http://www.weather.com.cn/data/sk/101010100.html http://www.weather.com.cn/data/cityinfo/10101 ...

  9. iOS-工厂模式

    概述 在前面两章中,分别介绍了简单工厂模式和工厂方法模式,我们知道简单工厂模式的优点是去除了客户端与具体产品的依赖,缺点是违反了“开放-关闭原则”:工厂方法模式克服了简单工厂模式的缺点,将产品的创建工 ...

  10. Android ListView 常用技巧

    Android ListView 常用技巧 Android TextView 常用技巧 1.使用ViewHolder提高效率 ViewHolder模式充分利用了ListView的视图缓存机制,避免了每 ...