Ich benutze this seit einiger Zeit:
SUBSTRING(str_col, PATINDEX('%[^0]%', str_col), LEN(str_col))
In letzter Zeit habe ich jedoch ein Problem mit Spalten mit allen "0" -Zeichen wie "00000000" gefunden, da es nie ein Nicht-"0" -Zeichen zur Übereinstimmung findet.
Eine alternative Technik, die ich gesehen habe, ist TRIM
:
REPLACE(LTRIM(REPLACE(str_col, '0', ' ')), ' ', '0')
Dies hat ein Problem, wenn eingebettete Leerzeichen vorhanden sind, da diese in "0" umgewandelt werden, wenn die Leerzeichen wieder in "0" umgewandelt werden.
Ich versuche, eine skalare UDF zu vermeiden. Ich habe in SQL Server 2005 zahlreiche Leistungsprobleme mit UDFs gefunden.
SUBSTRING(str_col, PATINDEX('%[^0]%', str_col+'.'), LEN(str_col))
Warum wandeln Sie den Wert nicht einfach in INTEGER
und dann wieder in VARCHAR
um?
SELECT CAST(CAST('000000000' AS INTEGER) AS VARCHAR)
--------
0
Andere Antworten hier nicht berücksichtigt, wenn Sie alle Nullen (oder sogar eine einzelne Null) haben.
Einige setzen einen leeren String standardmäßig auf Null, was falsch ist, wenn er leer bleiben soll.
Lesen Sie die ursprüngliche Frage erneut. Dies beantwortet, was der Fragesteller möchte.
--This example uses both Leading and Trailing zero's.
--Avoid losing those Trailing zero's and converting embedded spaces into more zeros.
--I added a non-whitespace character ("_") to retain trailing zero's after calling Replace().
--Simply remove the RTrim() function call if you want to preserve trailing spaces.
--If you treat zero's and empty-strings as the same thing for your application,
-- then you may skip the Case-Statement entirely and just use CN.CleanNumber .
DECLARE @WackadooNumber VarChar(50) = ' 0 0123ABC D0 '--'000'--
SELECT WN.WackadooNumber, CN.CleanNumber,
(CASE WHEN WN.WackadooNumber LIKE '%0%' AND CN.CleanNumber = '' THEN '0' ELSE CN.CleanNumber END)[AllowZero]
FROM (SELECT @WackadooNumber[WackadooNumber]) AS WN
OUTER APPLY (SELECT RTRIM(RIGHT(WN.WackadooNumber, LEN(LTRIM(REPLACE(WN.WackadooNumber + '_', '0', ' '))) - 1))[CleanNumber]) AS CN
--Result: "123ABC D0"
SELECT O.Type, O.Value, Parsed.Value[WrongValue],
(CASE WHEN CHARINDEX('0', T.Value) > 0--If there's at least one zero.
AND LEN(Parsed.Value) = 0--And the trimmed length is zero.
THEN '0' ELSE Parsed.Value END)[FinalValue],
(CASE WHEN CHARINDEX('0', T.Value) > 0--If there's at least one zero.
AND LEN(Parsed.TrimmedValue) = 0--And the trimmed length is zero.
THEN '0' ELSE LTRIM(RTRIM(Parsed.TrimmedValue)) END)[FinalTrimmedValue]
FROM
(
VALUES ('Null', NULL), ('EmptyString', ''),
('Zero', '0'), ('Zero', '0000'), ('Zero', '000.000'),
('Spaces', ' 0 A B C '), ('Number', '000123'),
('AlphaNum', '000ABC123'), ('NoZero', 'NoZerosHere')
) AS O(Type, Value)--O is for Original.
CROSS APPLY
( --This Step is Optional. Use if you also want to remove leading spaces.
SELECT LTRIM(RTRIM(O.Value))[Value]
) AS T--T is for Trimmed.
CROSS APPLY
( --From @CadeRoux's Post.
SELECT SUBSTRING(O.Value, PATINDEX('%[^0]%', O.Value + '.'), LEN(O.Value))[Value],
SUBSTRING(T.Value, PATINDEX('%[^0]%', T.Value + '.'), LEN(T.Value))[TrimmedValue]
) AS Parsed
Sie könnten das, was ich oben habe, für eine einmalige Entfernung von führenden Nullen verwenden.
Wenn Sie eine häufige Wiederverwendung planen, platzieren Sie sie in einer Inline-Table-Valued-Function (ITVF).
.__ Ihre Bedenken in Bezug auf Leistungsprobleme bei UDFs sind verständlich.
Dieses Problem gilt jedoch nur für All-Scalar-Funktionen und Multi-Statement-Table-Funktionen.
Die Verwendung von ITVFs ist vollkommen in Ordnung.
Ich habe das gleiche Problem mit unserer Datenbank von Drittanbietern.
Mit alphanumerischen Feldern werden viele ohne die führenden Leerzeichen eingegeben, dang menschen!
Dies macht Joins unmöglich, ohne die fehlenden führenden Nullen zu bereinigen.
Anstatt die führenden Nullen zu entfernen, sollten Sie in Betracht ziehen, Ihre getrimmten Werte nur mit führenden Nullen aufzufüllen, wenn Sie Ihre Joins ausführen.
Besser noch, bereinigen Sie Ihre Daten in der Tabelle, indem Sie führende Nullen hinzufügen und dann die Indizes neu erstellen.
Ich denke, das wäre viel schneller und weniger komplex.
SELECT RIGHT('0000000000' + LTRIM(RTRIM(NULLIF(' 0A10 ', ''))), 10)--0000000A10
SELECT RIGHT('0000000000' + LTRIM(RTRIM(NULLIF('', ''))), 10)--NULL --When Blank.
Ersetzen Sie anstelle eines Leerzeichens die 0 durch ein "seltenes" Leerzeichen, das normalerweise nicht im Text der Spalte enthalten sein sollte. Ein Zeilenvorschub ist wahrscheinlich gut genug für eine solche Kolonne. Dann können Sie normal LTrim und das Sonderzeichen wieder durch 0 ersetzen.
Folgendes gibt '0' zurück, wenn die Zeichenfolge vollständig aus Nullen besteht:
CASE WHEN SUBSTRING(str_col, PATINDEX('%[^0]%', str_col+'.'), LEN(str_col)) = '' THEN '0' ELSE SUBSTRING(str_col, PATINDEX('%[^0]%', str_col+'.'), LEN(str_col)) END AS str_col
Dies macht eine schöne Funktion ....
DROP FUNCTION [dbo].[FN_StripLeading]
GO
CREATE FUNCTION [dbo].[FN_StripLeading] (@string VarChar(128), @stripChar VarChar(1))
RETURNS VarChar(128)
AS
BEGIN
-- http://stackoverflow.com/questions/662383/better-techniques-for-trimming-leading-zeros-in-sql-server
DECLARE @retVal VarChar(128),
@pattern varChar(10)
SELECT @pattern = '%[^'[email protected]+']%'
SELECT @retVal = CASE WHEN SUBSTRING(@string, PATINDEX(@pattern, @string+'.'), LEN(@string)) = '' THEN @stripChar ELSE SUBSTRING(@string, PATINDEX(@pattern, @string+'.'), LEN(@string)) END
RETURN (@retVal)
END
GO
GRANT EXECUTE ON [dbo].[FN_StripLeading] TO PUBLIC
cast (Wert als int) funktioniert immer, wenn string eine Zahl ist
replace(ltrim(replace(Fieldname.TableName, '0', '')), '', '0')
Der Vorschlag von Thomas G. hat sich für unsere Bedürfnisse eingesetzt.
In unserem Fall war das Feld bereits String und nur die führenden Nullen mussten abgeschnitten werden. Meistens ist das alles numerisch, aber manchmal gibt es Buchstaben, so dass die vorherige INT-Konvertierung abstürzen würde.
Wenn Sie Snowflake SQL verwenden, können Sie Folgendes verwenden:
ltrim(str_col,'0')
Die ltrim-Funktion entfernt alle Instanzen des angegebenen Zeichensatzes von der linken Seite.
Ltrim (str_col, '0') auf '00000008A' würde also '8A' zurückgeben
Und rtrim (str_col, '0.') Für '$ 125.00' würde '$ 125' zurückgeben
Meine Version davon ist eine Adaption von Arvos Arbeit, mit etwas mehr, um zwei weitere Fälle zu gewährleisten.
1) Wenn wir alle 0 haben, sollten wir die Ziffer 0 zurückgeben.
2) Wenn wir ein Leerzeichen haben, sollten wir trotzdem ein Leerzeichen zurückgeben.
CASE
WHEN PATINDEX('%[^0]%', str_col + '.') > LEN(str_col) THEN RIGHT(str_col, 1)
ELSE SUBSTRING(str_col, PATINDEX('%[^0]%', str_col + '.'), LEN(str_col))
END
SELECT CAST(CAST('000000000' AS INTEGER) AS VARCHAR)
Dies hat eine Begrenzung für die Länge der Zeichenfolge, die in ein INT konvertiert werden kann
Wenn Sie nicht in int konvertieren möchten, bevorzuge ich die folgende Logik, da sie mit Nullen umgehen kann. IFNULL (Feld, LTRIM (Feld, '0'))