Ответ 1
SUBSTRING(str_col, PATINDEX('%[^0]%', str_col+'.'), LEN(str_col))
Я использовал этот в течение некоторого времени:
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.
SUBSTRING(str_col, PATINDEX('%[^0]%', str_col+'.'), LEN(str_col))
Почему бы вам просто не присвоить значение INTEGER
, а затем вернуться к VARCHAR
?
SELECT CAST(CAST('000000000' AS INTEGER) AS VARCHAR)
--------
0
Другие ответы здесь, чтобы не принимать во внимание, если у вас есть все ноль (или даже один ноль).
Некоторые всегда устанавливают пустую строку в ноль, что неверно, когда она должна оставаться пустой.
Перечитайте исходный вопрос. Это отвечает тому, чего хочет Участник.
--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"
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
Вы могли бы использовать то, что у меня было выше, для одноразового удаления начального нуля.
Если вы планируете многократно использовать его, поместите его в 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.
Вместо пробела замените 0 на "редкий" символ пробела, который обычно не должен быть в тексте столбца. Линейный канал, вероятно, достаточно хорош для столбца, подобного этому. Затем вы можете LTrim нормально и снова заменить специальный символ.
Далее возвращается '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
Это делает приятную функцию....
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 (value as int) всегда будет работать, если строка является числом
Моя версия этого является адаптацией работы 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
replace(ltrim(replace(Fieldname.TableName, '0', '')), '', '0')
Предложение Thomas G работало для наших нужд.
Поле в нашем случае уже было строкой, и нужно было только обрезать только начальные нули. В основном все числовые, но иногда есть буквы, поэтому предыдущее преобразование INT сбой.
Попробуйте следующее:
replace(ltrim(replace(@str, '0', ' ')), ' ', '0')