Лучшие методы обрезки ведущих нулей в SQL Server?

Я использовал этот в течение некоторого времени:

SUBSTRING(str_col, PATINDEX('%[^0]%', str_col), LEN(str_col))

В последнее время я обнаружил проблему со столбцами со всеми символами "0", такими как "00000000", потому что он никогда не находит символ "0" для соответствия.

Альтернативный метод, который я видел, это использовать TRIM:

REPLACE(LTRIM(REPLACE(str_col, '0', ' ')), ' ', '0')

У этого есть проблема, если есть встроенные пробелы, потому что они будут превращены в "0", когда пространства вернутся в "0" s.

Я пытаюсь избежать скалярного UDF. Я нашел много проблем с производительностью с UDF в SQL Server 2005.

Ответ 1

SUBSTRING(str_col, PATINDEX('%[^0]%', str_col+'.'), LEN(str_col))

Ответ 2

Почему бы вам просто не присвоить значение INTEGER, а затем вернуться к VARCHAR?

SELECT  CAST(CAST('000000000' AS INTEGER) AS VARCHAR)

--------
       0

Ответ 3

Другие ответы здесь, чтобы не принимать во внимание, если у вас есть все ноль (или даже один ноль).
Некоторые всегда устанавливают пустую строку в ноль, что неверно, когда она должна оставаться пустой.
Перечитайте исходный вопрос. Это отвечает тому, чего хочет Участник.

Решение №1:

--This example uses both Leading and Trailing zero's.
--Avoid losing those Trailing zero and converting embedded spaces into more zeros.
--I added a non-whitespace character ("_") to retain trailing zero after calling Replace().
--Simply remove the RTrim() function call if you want to preserve trailing spaces.
--If you treat zero 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"

Решение №2 (с данными примера):

SELECT O.Type, O.Value, Parsed.Value[WrongValue],
       (CASE WHEN CHARINDEX('0', T.Value)  > 0--If there 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 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 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

Результаты:

MikeTeeVee_SQL_Server_Remove_Leading_Zeros

Резюме:

Вы могли бы использовать то, что у меня было выше, для одноразового удаления начального нуля.
Если вы планируете многократно использовать его, поместите его в Inline-Table-Valued-Function (ITVF).
Ваши проблемы с проблемами производительности с UDF понятны.
Однако эта проблема применима только к All-Scalar-Functions и Multi-Statement-Table-Functions.
Использование ITVF прекрасно.


У меня такая же проблема с нашей базой данных сторонних разработчиков.
С альфа-числовыми полями многие вводятся без ведущих пространств, забивают людей!
Это делает невозможным объединение без очистки недостающих начальных нулей.

Вывод:

Вместо того, чтобы удалять ведущие нули, вы можете захотеть просто заполнить ваши обрезанные значения ведущими нулями, когда вы делаете свои соединения.
Еще лучше очистите данные в таблице, добавив ведущие нули, а затем перестройте свои индексы.
Я думаю, что это будет быстрее и менее сложно.

SELECT RIGHT('0000000000' + LTRIM(RTRIM(NULLIF(' 0A10  ', ''))), 10)--0000000A10
SELECT RIGHT('0000000000' + LTRIM(RTRIM(NULLIF('', ''))), 10)--NULL --When Blank.

Ответ 4

Вместо пробела замените 0 на "редкий" символ пробела, который обычно не должен быть в тексте столбца. Линейный канал, вероятно, достаточно хорош для столбца, подобного этому. Затем вы можете LTrim нормально и снова заменить специальный символ.

Ответ 5

Далее возвращается '0', если строка целиком состоит из нулей:

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

Ответ 6

Это делает приятную функцию....

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

Ответ 7

cast (value as int) всегда будет работать, если строка является числом

Ответ 8

Моя версия этого является адаптацией работы Arvo, с немного более добавленной для обеспечения двух других случаев.

1) Если мы имеем все 0s, мы должны вернуть цифру 0.

2) Если у нас есть пробел, мы все равно должны вернуть пустой символ.

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

Ответ 9

replace(ltrim(replace(Fieldname.TableName, '0', '')), '', '0')

Предложение Thomas G работало для наших нужд.

Поле в нашем случае уже было строкой, и нужно было только обрезать только начальные нули. В основном все числовые, но иногда есть буквы, поэтому предыдущее преобразование INT сбой.

Ответ 10

Попробуйте следующее:

replace(ltrim(replace(@str, '0', ' ')), ' ', '0')