Odpowiedzi:
Jest to po prostu nieefektywne użycie SQL, bez względu na to, jak to robisz.
może coś takiego
right('XXXXXXXXXXXX'+ rtrim(@str), @n)
gdzie X jest znakiem dopełniania, a @n jest liczbą znaków w wynikowym ciągu (zakładając, że potrzebujesz dopełnienia, ponieważ masz do czynienia ze stałą długością).
Ale jak powiedziałem, naprawdę powinieneś unikać robienia tego w swojej bazie danych.
RTRIM(@str)
jeśli może zawierać końcowe spacje.
Wiem, że pierwotnie o to pytano w 2008 r., Ale w SQL Server 2012 wprowadzono kilka nowych funkcji. Funkcja FORMAT ładnie upraszcza wypełnianie zer zerami. Przeprowadzi również konwersję dla Ciebie:
declare @n as int = 2
select FORMAT(@n, 'd10') as padWithZeros
Aktualizacja:
Chciałem sam przetestować rzeczywistą wydajność funkcji FORMAT. Byłem dość zaskoczony, gdy stwierdziłem, że wydajność nie była bardzo dobra w porównaniu z pierwotną odpowiedzią AlexCuse . Chociaż uważam, że funkcja FORMAT jest czystsza, nie jest ona zbyt wydajna pod względem czasu wykonania. Użyta przeze mnie tabela Tally ma 64 000 rekordów. Wyrazy uznania dla Martina Smitha za wskazanie wydajności czasu wykonania.
SET STATISTICS TIME ON
select FORMAT(N, 'd10') as padWithZeros from Tally
SET STATISTICS TIME OFF
Czasy wykonania programu SQL Server: czas procesora = 2157 ms, czas, który upłynął = 2696 ms.
SET STATISTICS TIME ON
select right('0000000000'+ rtrim(cast(N as varchar(5))), 10) from Tally
SET STATISTICS TIME OFF
Czasy wykonania programu SQL Server:
Czas procesora = 31 ms, czas, który upłynął = 235 ms.
Być może nadmierne zabójstwo mam te UDF-y, które można przewrócić w lewo i w prawo
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
i na prawo
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
Nie jestem pewien, czy podana metoda jest naprawdę nieefektywna, ale będzie to alternatywny sposób, o ile nie musi ona być elastyczna pod względem długości lub znaku dopełniania (zakładając, że chcesz ją uzupełnić za pomocą „ 0 "do 10 znaków:
DECLARE
@pad_characters VARCHAR(10)
SET @pad_characters = '0000000000'
SELECT RIGHT(@pad_characters + @str, 10)
prawdopodobnie przesada, często używam tego 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
Abyś mógł robić takie rzeczy jak:
select dbo.f_pad_before('aaa', 10, '_')
jest to prosty sposób na wstawienie lewej strony:
REPLACE(STR(FACT_HEAD.FACT_NO, x, 0), ' ', y)
Gdzie x
jest numer pada i y
znak pada.
próba:
REPLACE(STR(FACT_HEAD.FACT_NO, 3, 0), ' ', 0)
1
stają 001
.
select right(replicate(@padchar, @len) + @str, @len)
Używam tego. Pozwala określić długość, która ma być wynikiem, a także domyślny znak dopełniający, jeśli nie zostanie podany. Oczywiście możesz dostosować długość danych wejściowych i wyjściowych dla dowolnych maksymalnych poziomów.
/*===============================================================
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
Twój przebieg może się różnić. :-)
Joey Morgan
programista / główny analityk I
WellPoint Medicaid Business Unit
Oto moje rozwiązanie, które pozwala uniknąć skróconych ciągów znaków i używa zwykłego ol 'SQL. Dzięki @AlexCuse , @Kevin i @Sklivvz , których rozwiązania są podstawą tego kodu.
--[@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;
Wiem, że w tej chwili nie ma to większego znaczenia w rozmowie, ale uruchamiam procedurę generowania plików, która idzie niesamowicie wolno. Użyłem replikacji i widziałem tę metodę przycinania i pomyślałem, że dam jej szansę.
W moim kodzie widać, że przełączanie między nimi jest dodatkiem do nowej zmiennej @padding (i istniejącego ograniczenia). Uruchomiłem procedurę z funkcją w obu stanach z tymi samymi wynikami w czasie wykonania. Tak więc przynajmniej w SQLServer2016 nie widzę żadnej różnicy w wydajności, którą inni stwierdzili.
Tak czy inaczej, oto mój UDF, który napisałem lata temu, oraz dzisiejsze zmiany, które są w dużej mierze takie same jak inne, oprócz tego, że ma opcję LEWEGO / PRAWEGO parametru i sprawdzanie błędów.
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
Mam jedną funkcję, która lpad z dziesiętnymi x: UTWÓRZ FUNKCJĘ [dbo]. [LPAD_DEC] (- Dodaj parametry funkcji tutaj @pad nvarchar (MAX), @string nvarchar (MAX), @length int, @dec int ) ZWRACA nvarchar (max) AS BEGIN - Deklaruj tutaj zmienną zwrotną DEKLARUJ @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
KONIEC
Aby podać wartości liczbowe zaokrąglone do dwóch miejsc po przecinku, ale w razie potrzeby uzupełnione zerami, mam:
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)
Byłoby to mile widziane, jeśli ktoś mógłby wymyślić lepszy sposób - powyższe wydaje się niezdarne .
Uwaga : w tym przypadku używam programu SQL Server do wysyłania raportów pocztą e-mail w formacie HTML, dlatego chcę sformatować informacje bez udziału dodatkowego narzędzia do analizy danych.