用前导零填充字符串,使其在 SQL Server 2008 中的长度为 3 个字符
Posted
技术标签:
【中文标题】用前导零填充字符串,使其在 SQL Server 2008 中的长度为 3 个字符【英文标题】:Pad a string with leading zeros so it's 3 characters long in SQL Server 2008 【发布时间】:2013-05-21 14:03:18 【问题描述】:在 SQL Server 2008 R2 中首次创建时,我有一个最长为 3 个字符的字符串。
我想用前导零填充它,所以如果它的原始值是“1”,那么新值就是“001”。或者,如果它的原始值为“23”,则新值为“023”。或者如果它的原始值为 '124' 则新值与原始值相同。
我正在使用 SQL Server 2008 R2。我将如何使用 T-SQL 做到这一点?
【问题讨论】:
Most efficient T-SQL way to pad a varchar on the left to a certain length?的可能重复 Formatting Numbers by padding with leading zeros in SQL Server的可能重复 【参考方案1】:如果该字段已经是一个字符串,这将起作用
SELECT RIGHT('000'+ISNULL(field,''),3)
如果您希望 null 显示为 '000'
它可能是一个整数——那么你会想要
SELECT RIGHT('000'+CAST(field AS VARCHAR(3)),3)
根据问题的要求,此答案仅在长度 '0000' and VARCHAR(4)),4
【讨论】:
我有一个 Char(6) 字段,其中包含一些只有 2-3 个字符长的值,而上述内容对我不起作用。我必须在 '000000'+ISNULL(FIELD,'') 周围添加一个 RTRIM 才能正常工作。 Hogan 是的,我明白了,但不管字符串有多长它都不起作用,我有点太忙了,不知道为什么,但它的要点是我的 CHAR(6 ) 字段只是做 RIGHT('000000'+ISNULL(field,''),6) 没有工作,但 RIGHT(RTRIM('000000'+ISNULL(field,'')),6) 做。 哦,我明白了,编码为字符串的数字右侧有空格。 @dwiener 你得到这个行为是因为 char 是一个固定长度的数据类型,所以在你的情况下 char(6) 意味着 6 个字符长。如果您的实际值小于 6,则会在右侧填充空白,因此建议的答案会为 char(6) 产生不正确的结果。 @Hogan,是的,但是这个问题是“sql 添加前导零”的前 1 个谷歌结果,所以我认为这对很多人(不使用 sqlserver,但谷歌这个问题)很有用) 要知道在其他数据库中可能存在更方便的函数 lpad。还是谢谢你。【参考方案2】:虽然问题是针对 SQL Server 2008 R2,但如果有人正在使用 2012 及更高版本阅读此内容,那么使用FORMAT 会变得更加容易。
您可以传递 standard numeric format string 或 custom numeric format string 作为格式参数(感谢 Vadim Ovchinnikov 的提示)。
对于这个问题,例如一个类似的代码
DECLARE @myInt INT = 1;
-- One way using a standard numeric format string
PRINT FORMAT(@myInt,'D3');
-- Other way using a custom numeric format string
PRINT FORMAT(@myInt,'00#');
输出
001
001
【讨论】:
如果输入的数字是111或11会怎样? 1 是 001,11 是 011,111 是 111 你可以用'D3'代替'00#'。 它似乎比接受的答案要慢得多,但如果不处理大量数据会容易得多 虽然看起来不合逻辑,但值得注意的是,FORMAT 仅适用于数字和日期类型,不适用于 varchar。【参考方案3】:安全的方法:
SELECT REPLACE(STR(n,3),' ','0')
这具有返回字符串 '***'
for n 999 的优点,这是一个很好且明显的越界输入指示。此处列出的其他方法将通过将输入截断为 3 个字符的子字符串来静默失败。
【讨论】:
该死,登陆这个页面的人应该帮助这个浮动到顶部! 小心这种方法。当表达式超过指定长度时,字符串返回指定长度的**。例如str(n, 10),当 n = 1000000000 时,会出现星星 (*)。 我不知道它是如何工作的,但它很棒而且很简单。 小心这个,字符串会破坏它(并且OP要求“填充字符串”)。作品:SELECT REPLACE(STR('1',3),' ','0')
休息:SELECT REPLACE(STR('1A',3),' ','0')
。今天,当用户在输入字符串中输入一个字母而我未能测试这种情况时,这让我很生气。
@Unbound 这就是它的工作方式,海报已经说过了。最好返回 ***,而不是像所有其他建议那样返回截断值,这表明参数错误。【参考方案4】:
这是我在 SQL Server Express 2012 中使用的 Hogan 答案的变体:
SELECT RIGHT(CONCAT('000', field), 3)
不用担心该字段是否为字符串,我只需CONCAT
它,因为它无论如何都会输出一个字符串。此外,如果该字段可以是 NULL
,则可能需要使用 ISNULL
以避免函数获取 NULL
结果。
SELECT RIGHT(CONCAT('000', ISNULL(field,'')), 3)
【讨论】:
据我所知,CONCAT 只是忽略该值,如果它为空,所以第一个可以正常工作。 无论字段的长度如何,此解决方案都可以使用 小心,如果字段长度大于 3,这个解决方案会中断。 SELECT RIGHT(CONCAT('000', '87679'), 3) --> 679 如果长度大于三,你可以这样解决问题:SELECT RIGHT(CONCAT('000', field), CASE WHEN LEN(field) 【参考方案5】:这是一种更通用的技术,可以将左填充到任何所需的宽度:
declare @x int = 123 -- value to be padded
declare @width int = 25 -- desired width
declare @pad char(1) = '0' -- pad character
select right_justified = replicate(
@pad ,
@width-len(convert(varchar(100),@x))
)
+ convert(varchar(100),@x)
但是,如果您要处理负值并使用前导零填充,则此方法或其他建议的技术都不起作用。你会得到如下所示的东西:
00-123
[可能不是你想要的]
所以……您将不得不跳过一些额外的障碍这是一种可以正确格式化负数的方法:
declare @x float = -1.234
declare @width int = 20
declare @pad char(1) = '0'
select right_justified = stuff(
convert(varchar(99),@x) , -- source string (converted from numeric value)
case when @x < 0 then 2 else 1 end , -- insert position
0 , -- count of characters to remove from source string
replicate(@pad,@width-len(convert(varchar(99),@x)) ) -- text to be inserted
)
应该注意convert()
调用应该指定一个足够长的[n]varchar
来保存带有截断的转换结果。
【讨论】:
@StenPetrov,谢谢。这完全取决于您要完成的工作。我学会了在大型现实世界生产数据库中依赖的一件事是存在一种或另一种不良数据。如果可能的话,我更愿意避免凌晨 3 点的电话;^) :) 当凌晨 3 点的电话打进来时,我宁愿阅读 1 条简单的线路而不是 10 条复杂的线路。添加变量进一步使事情变得更糟,特别是如果另一个团队成员决定即时计算它们并且没有检查非负的@width... 那些添加的变量只是为了概括——你可以硬编码这些值。对于一个衬垫,您可以创建一个标量函数 - 然后您就有了一个衬垫。【参考方案6】:我一直觉得下面这个方法很有帮助。
REPLICATE('0', 5 - LEN(Job.Number)) + CAST(Job.Number AS varchar) as 'NumberFull'
【讨论】:
【参考方案7】:使用适合各种情况的此功能。
CREATE FUNCTION dbo.fnNumPadLeft (@input INT, @pad tinyint)
RETURNS VARCHAR(250)
AS BEGIN
DECLARE @NumStr VARCHAR(250)
SET @NumStr = LTRIM(@input)
IF(@pad > LEN(@NumStr))
SET @NumStr = REPLICATE('0', @Pad - LEN(@NumStr)) + @NumStr;
RETURN @NumStr;
END
样本输出
SELECT [dbo].[fnNumPadLeft] (2016,10) -- returns 0000002016
SELECT [dbo].[fnNumPadLeft] (2016,5) -- returns 02016
SELECT [dbo].[fnNumPadLeft] (2016,2) -- returns 2016
SELECT [dbo].[fnNumPadLeft] (2016,0) -- returns 2016
【讨论】:
这应该是公认的答案,因为它适用于数字和字符串。如果您不想使用函数(但为什么不使用),类似的方法也可以:DECLARE @NumStr VARCHAR(250) = '2016'; SELECT REPLICATE('0', 12 - LEN(@NumStr)) + @NumStr;
返回上面 Salar 的第一个示例。谢谢撒拉。
我上面的评论有错字,应该是:DECLARE @NumStr VARCHAR(250) = '2016'; SELECT REPLICATE('0', 10 - LEN(@NumStr)) + @NumStr;
,在上面的第一个例子中返回0000002016
。
@JeffMergler - 这对数字和字符串有什么作用?它是一个接受整数参数的函数。问题是关于字符串的。【参考方案8】:
对于那些想要更新他们现有数据的人来说,这里是查询:
update SomeEventTable set eventTime=RIGHT('00000'+ISNULL(eventTime, ''),5)
【讨论】:
【参考方案9】:我知道这是一张旧票,但我只是想分享一下:
我发现这段代码提供了一个解决方案。不确定它是否适用于所有版本的 MSSQL;我有 MSSQL 2016。
declare @value as nvarchar(50) = 23
select REPLACE(STR(CAST(@value AS INT) + 1,4), SPACE(1), '0') as Leadingzero
这将返回“0023”。
STR函数中的4是总长度,包括数值。例如,4、23 和 123 在 STR 中都将有 4,并且将添加正确数量的零。您可以增加或减少它。无需获取 23 的长度。
编辑:我看到它与@Anon 的帖子相同。
【讨论】:
【参考方案10】:对于整数,您可以使用从 int 到 varchar 的隐式转换:
SELECT RIGHT(1000 + field, 3)
【讨论】:
但是,如果值足够大,这将失败,此外,对于负值,您会得到...有趣的结果。【参考方案11】:用固定长度试试这个。
select right('000000'+'123',5)
select REPLICATE('0', 5 - LEN(123)) + '123'
【讨论】:
【参考方案12】:当我需要固定大小的 varchar(或字符串)输出时,我在将整数列作为输入时遇到了类似的问题。例如,1 到“01”,12 到“12”。此代码有效:
SELECT RIGHT(CONCAT('00',field::text),2)
如果输入也是一列varchar,可以避免强制转换部分。
【讨论】:
【参考方案13】:对于更动态的方法,试试这个。
declare @val varchar(5)
declare @maxSpaces int
set @maxSpaces = 3
set @val = '3'
select concat(REPLICATE('0',@maxSpaces-len(@val)),@val)
【讨论】:
【参考方案14】:写这个是因为我有一个特定长度的要求 (9)。 仅当输入需要填充时,才使用 @pattern 填充左侧。 应始终返回 @pattern 中定义的长度。
declare @charInput as char(50) = 'input'
--always handle NULL :)
set @charInput = isnull(@charInput,'')
declare @actualLength as int = len(@charInput)
declare @pattern as char(50) = '123456789'
declare @prefLength as int = len(@pattern)
if @prefLength > @actualLength
select Left(Left(@pattern, @prefLength-@actualLength) + @charInput, @prefLength)
else
select @charInput
返回 1234 输入
【讨论】:
【参考方案15】:很简单
喜欢:
DECLARE @DUENO BIGINT
SET @DUENO=5
SELECT 'ND'+STUFF('000000',6-LEN(RTRIM(@DueNo))+1,LEN(RTRIM(@DueNo)),RTRIM(@DueNo)) DUENO
【讨论】:
【参考方案16】:我专门来这里研究如何将我的 timezoneoffset 转换为 timezone 字符串,以便在 SQL Server 2008 中将日期转换为 DATETIMEOFFSET。粗略,但必要。
所以我需要一种方法来处理负数和正数,如果需要,将它们格式化为两个带有前导零的字符。 Anons answer 让我很接近,但负时区值会显示为 0-5
而不是必需的 -05
因此,对他的回答稍作调整,这适用于所有时区小时转换
DECLARE @n INT = 13 -- Works with -13, -5, 0, 5, etc
SELECT CASE
WHEN @n < 0 THEN '-' + REPLACE(STR(@n * -1 ,2),' ','0')
ELSE '+' + REPLACE(STR(@n,2),' ','0') END + ':00'
【讨论】:
【参考方案17】:我创建了这个函数,它满足 bigint 和一个前导零或其他单个字符(最多返回 20 个字符),并允许结果长度小于输入数字的长度:
create FUNCTION fnPadNum (
@Num BIGINT --Number to be padded, @sLen BIGINT --Total length of results , @PadChar varchar(1))
RETURNS VARCHAR(20)
AS
--Pads bigint with leading 0's
--Sample: "select dbo.fnPadNum(201,5,'0')" returns "00201"
--Sample: "select dbo.fnPadNum(201,5,'*')" returns "**201"
--Sample: "select dbo.fnPadNum(201,5,' ')" returns " 201"
BEGIN
DECLARE @Results VARCHAR(20)
SELECT @Results = CASE
WHEN @sLen >= len(ISNULL(@Num, 0))
THEN replicate(@PadChar, @sLen - len(@Num)) + CAST(ISNULL(@Num, 0) AS VARCHAR)
ELSE CAST(ISNULL(@Num, 0) AS VARCHAR)
END
RETURN @Results
END
GO
--Usage:
SELECT dbo.fnPadNum(201, 5,'0')
SELECT dbo.fnPadNum(201, 5,'*')
SELECT dbo.fnPadNum(201, 5,' ')
【讨论】:
以上是关于用前导零填充字符串,使其在 SQL Server 2008 中的长度为 3 个字符的主要内容,如果未能解决你的问题,请参考以下文章