Risposte:
Questo è semplicemente un uso inefficiente di SQL, indipendentemente da come lo si fa.
forse qualcosa del genere
right('XXXXXXXXXXXX'+ rtrim(@str), @n)
dove X è il tuo carattere di riempimento e @n è il numero di caratteri nella stringa risultante (supponendo che tu abbia bisogno del riempimento perché hai a che fare con una lunghezza fissa).
Ma come ho detto, dovresti davvero evitare di farlo nel tuo database.
RTRIM(@str)
però se questo può contenere spazi finali.
So che questo è stato originariamente richiesto nel 2008, ma ci sono alcune nuove funzioni introdotte con SQL Server 2012. La funzione FORMAT semplifica il riempimento lasciato con zeri. Eseguirà anche la conversione per te:
declare @n as int = 2
select FORMAT(@n, 'd10') as padWithZeros
Aggiornare:
Volevo testare personalmente l'effettiva efficienza della funzione FORMAT. Sono stato piuttosto sorpreso di scoprire che l'efficienza non era molto buona rispetto alla risposta originale di AlexCuse . Anche se trovo la funzione FORMAT più pulita, non è molto efficiente in termini di tempo di esecuzione. La tabella Tally che ho usato ha 64.000 record. Complimenti a Martin Smith per aver sottolineato l'efficienza dei tempi di esecuzione.
SET STATISTICS TIME ON
select FORMAT(N, 'd10') as padWithZeros from Tally
SET STATISTICS TIME OFF
Tempi di esecuzione di SQL Server: tempo CPU = 2157 ms, tempo trascorso = 2696 ms.
SET STATISTICS TIME ON
select right('0000000000'+ rtrim(cast(N as varchar(5))), 10) from Tally
SET STATISTICS TIME OFF
Tempi di esecuzione di SQL Server:
Tempo CPU = 31 ms, tempo trascorso = 235 ms.
Forse un'uccisione eccessiva ho questi UDF da colpire a destra e a sinistra
ALTER Function [dbo].[fsPadLeft](@var varchar(200),@padChar char(1)='0',@len int)
returns varchar(300)
as
Begin
return replicate(@PadChar,@len-Len(@var))+@var
end
ea destra
ALTER function [dbo].[fsPadRight](@var varchar(200),@padchar char(1)='0', @len int) returns varchar(201) as
Begin
--select @padChar=' ',@len=200,@var='hello'
return @var+replicate(@PadChar,@len-Len(@var))
end
Non sono sicuro che il metodo che dai sia davvero inefficiente, ma un modo alternativo, purché non debba essere flessibile nella lunghezza o nel carattere di riempimento, sarebbe (supponendo che tu voglia riempirlo con " Da 0 "a 10 caratteri:
DECLARE
@pad_characters VARCHAR(10)
SET @pad_characters = '0000000000'
SELECT RIGHT(@pad_characters + @str, 10)
probabilmente eccessivo, uso spesso questo UDF:
CREATE FUNCTION [dbo].[f_pad_before](@string VARCHAR(255), @desired_length INTEGER, @pad_character CHAR(1))
RETURNS VARCHAR(255) AS
BEGIN
-- Prefix the required number of spaces to bulk up the string and then replace the spaces with the desired character
RETURN ltrim(rtrim(
CASE
WHEN LEN(@string) < @desired_length
THEN REPLACE(SPACE(@desired_length - LEN(@string)), ' ', @pad_character) + @string
ELSE @string
END
))
END
In modo che tu possa fare cose come:
select dbo.f_pad_before('aaa', 10, '_')
questo è un modo semplice per passare a sinistra:
REPLACE(STR(FACT_HEAD.FACT_NO, x, 0), ' ', y)
Dov'è x
il numero del pad ed y
è il carattere del pad.
campione:
REPLACE(STR(FACT_HEAD.FACT_NO, 3, 0), ' ', 0)
1
diventano 001
.
select right(replicate(@padchar, @len) + @str, @len)
Io uso questo. Consente di determinare la lunghezza desiderata per il risultato e un carattere di riempimento predefinito se non viene fornito. Ovviamente puoi personalizzare la lunghezza dell'input e dell'output per qualunque sia il tuo massimo.
/*===============================================================
Author : Joey Morgan
Create date : November 1, 2012
Description : Pads the string @MyStr with the character in
: @PadChar so all results have the same length
================================================================*/
CREATE FUNCTION [dbo].[svfn_AMS_PAD_STRING]
(
@MyStr VARCHAR(25),
@LENGTH INT,
@PadChar CHAR(1) = NULL
)
RETURNS VARCHAR(25)
AS
BEGIN
SET @PadChar = ISNULL(@PadChar, '0');
DECLARE @Result VARCHAR(25);
SELECT
@Result = RIGHT(SUBSTRING(REPLICATE('0', @LENGTH), 1,
(@LENGTH + 1) - LEN(RTRIM(@MyStr)))
+ RTRIM(@MyStr), @LENGTH)
RETURN @Result
END
Il tuo chilometraggio può variare. :-)
Joey Morgan
Programmatore / Analista Principale I
WellPoint Business Unit Medicaid
Ecco la mia soluzione, che evita le stringhe troncate e utilizza semplicemente il vecchio SQL. Grazie a @AlexCuse , @Kevin e @Sklivvz , le cui soluzioni sono alla base di questo codice.
--[@charToPadStringWith] is the character you want to pad the string with.
declare @charToPadStringWith char(1) = 'X';
-- Generate a table of values to test with.
declare @stringValues table (RowId int IDENTITY(1,1) NOT NULL PRIMARY KEY, StringValue varchar(max) NULL);
insert into @stringValues (StringValue) values (null), (''), ('_'), ('A'), ('ABCDE'), ('1234567890');
-- Generate a table to store testing results in.
declare @testingResults table (RowId int IDENTITY(1,1) NOT NULL PRIMARY KEY, StringValue varchar(max) NULL, PaddedStringValue varchar(max) NULL);
-- Get the length of the longest string, then pad all strings based on that length.
declare @maxLengthOfPaddedString int = (select MAX(LEN(StringValue)) from @stringValues);
declare @longestStringValue varchar(max) = (select top(1) StringValue from @stringValues where LEN(StringValue) = @maxLengthOfPaddedString);
select [@longestStringValue]=@longestStringValue, [@maxLengthOfPaddedString]=@maxLengthOfPaddedString;
-- Loop through each of the test string values, apply padding to it, and store the results in [@testingResults].
while (1=1)
begin
declare
@stringValueRowId int,
@stringValue varchar(max);
-- Get the next row in the [@stringLengths] table.
select top(1) @stringValueRowId = RowId, @stringValue = StringValue
from @stringValues
where RowId > isnull(@stringValueRowId, 0)
order by RowId;
if (@@ROWCOUNT = 0)
break;
-- Here is where the padding magic happens.
declare @paddedStringValue varchar(max) = RIGHT(REPLICATE(@charToPadStringWith, @maxLengthOfPaddedString) + @stringValue, @maxLengthOfPaddedString);
-- Added to the list of results.
insert into @testingResults (StringValue, PaddedStringValue) values (@stringValue, @paddedStringValue);
end
-- Get all of the testing results.
select * from @testingResults;
So che questo non aggiunge molto alla conversazione a questo punto, ma sto eseguendo una procedura di generazione di file e sta andando incredibilmente lentamente. Ho usato replicare e ho visto questo metodo di taglio e ho pensato di provarlo.
Nel mio codice puoi vedere dove si trova il passaggio tra i due oltre alla nuova variabile @padding (e la limitazione che ora esiste). Ho eseguito la mia procedura con la funzione in entrambi gli stati con gli stessi risultati in fase di esecuzione. Quindi, almeno in SQLServer2016, non vedo alcuna differenza di efficienza che altri hanno riscontrato.
Ad ogni modo, ecco il mio UDF che ho scritto anni fa più le modifiche oggi, che è molto simile a quello degli altri, poiché ha un'opzione param SINISTRA / DESTRA e qualche controllo degli errori.
CREATE FUNCTION PadStringTrim
(
@inputStr varchar(500),
@finalLength int,
@padChar varchar (1),
@padSide varchar(1)
)
RETURNS VARCHAR(500)
AS BEGIN
-- the point of this function is to avoid using replicate which is extremely slow in SQL Server
-- to get away from this though we now have a limitation of how much padding we can add, so I've settled on a hundred character pad
DECLARE @padding VARCHAR (100) = 'XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX'
SET @padding = REPLACE(@padding, 'X', @padChar)
SET @inputStr = RTRIM(LTRIM(@inputStr))
IF LEN(@inputStr) > @finalLength
RETURN '!ERROR!' -- can search for ! in the returned text
ELSE IF(@finalLength > LEN(@inputStr))
IF @padSide = 'L'
SET @inputStr = RIGHT(@padding + @inputStr, @finalLength)
--SET @inputStr = REPLICATE(@padChar, @finalLength - LEN(@inputStr)) + @inputStr
ELSE IF @padSide = 'R'
SET @inputStr = LEFT(@inputStr + @padding, @finalLength)
--SET @inputStr = @inputStr + REPLICATE(@padChar, @finalLength - LEN(@inputStr))
-- if LEN(@inputStr) = @finalLength we just return it
RETURN @inputStr;
END
-- SELECT dbo.PadStringTrim( tblAccounts.account, 20, '~' , 'R' ) from tblAccounts
-- SELECT dbo.PadStringTrim( tblAccounts.account, 20, '~' , 'L' ) from tblAccounts
Ho una funzione che lpad con decimali x: CREATE FUNCTION [dbo]. [LPAD_DEC] (- Aggiungi qui i parametri della funzione @pad nvarchar (MAX), @string nvarchar (MAX), @length int, @dec int ) RESI nvarchar (max) COME INIZIO - Dichiarare qui la variabile di ritorno DECLARE @resp nvarchar (max)
IF LEN(@string)=@length
BEGIN
IF CHARINDEX('.',@string)>0
BEGIN
SELECT @resp = CASE SIGN(@string)
WHEN -1 THEN
-- Nros negativos grandes con decimales
concat('-',SUBSTRING(replicate(@pad,@length),1,@length-len(@string)),ltrim(str(abs(@string),@length,@dec)))
ELSE
-- Nros positivos grandes con decimales
concat(SUBSTRING(replicate(@pad,@length),1,@length-len(@string)),ltrim(str(@string,@length,@dec)))
END
END
ELSE
BEGIN
SELECT @resp = CASE SIGN(@string)
WHEN -1 THEN
--Nros negativo grande sin decimales
concat('-',SUBSTRING(replicate(@pad,@length),1,(@length-3)-len(@string)),ltrim(str(abs(@string),@length,@dec)))
ELSE
-- Nros positivos grandes con decimales
concat(SUBSTRING(replicate(@pad,@length),1,@length-len(@string)),ltrim(str(@string,@length,@dec)))
END
END
END
ELSE
IF CHARINDEX('.',@string)>0
BEGIN
SELECT @resp =CASE SIGN(@string)
WHEN -1 THEN
-- Nros negativos con decimales
concat('-',SUBSTRING(replicate(@pad,@length),1,@length-len(@string)),ltrim(str(abs(@string),@length,@dec)))
ELSE
--Ntos positivos con decimales
concat(SUBSTRING(replicate(@pad,@length),1,@length-len(@string)),ltrim(str(abs(@string),@length,@dec)))
END
END
ELSE
BEGIN
SELECT @resp = CASE SIGN(@string)
WHEN -1 THEN
-- Nros Negativos sin decimales
concat('-',SUBSTRING(replicate(@pad,@length-3),1,(@length-3)-len(@string)),ltrim(str(abs(@string),@length,@dec)))
ELSE
-- Nros Positivos sin decimales
concat(SUBSTRING(replicate(@pad,@length),1,(@length-3)-len(@string)),ltrim(str(abs(@string),@length,@dec)))
END
END
RETURN @resp
FINE
Per fornire valori numerici arrotondati al secondo decimale ma riempiti a destra con zeri, se necessario, ho:
DECLARE @value = 20.1
SET @value = ROUND(@value,2) * 100
PRINT LEFT(CAST(@value AS VARCHAR(20)), LEN(@value)-2) + '.' + RIGHT(CAST(@value AS VARCHAR(20)),2)
Se qualcuno potesse pensare a un modo più ordinato, questo sarebbe apprezzato - quanto sopra sembra goffo .
Nota : in questo caso, sto usando SQL Server per inviare report via email in formato HTML e quindi desidero formattare le informazioni senza coinvolgere uno strumento aggiuntivo per analizzare i dati.
Ecco come normalmente riempirei un varchar
WHILE Len(@String) < 8
BEGIN
SELECT @String = '0' + @String
END