16 ответов:
первый способ, который приходит на ум, это сделать это косвенно, заменив запятую пустой строкой и сравнив длины
Declare @string varchar(1000) Set @string = 'a,b,c,d' select len(@string) - len(replace(@string, ',', ''))
быстрое расширение ответа cmsjr, который работает для строк более чем более символов.
CREATE FUNCTION dbo.CountOccurrencesOfString ( @searchString nvarchar(max), @searchTerm nvarchar(max) ) RETURNS INT AS BEGIN return (LEN(@searchString)-LEN(REPLACE(@searchString,@searchTerm,'')))/LEN(@searchTerm) ENDиспользование:
SELECT * FROM MyTable where dbo.CountOccurrencesOfString(MyColumn, 'MyString') = 1
вы можете сравнить длину строки с той, где запятые удаляются:
len(value) - len(replace(value,',',''))
ответ @csmjr имеет проблему в некоторых случаях.
его ответ был таков:
Declare @string varchar(1000) Set @string = 'a,b,c,d' select len(@string) - len(replace(@string, ',', ''))это работает в большинстве сценариев, однако, попробуйте запустить это:
DECLARE @string VARCHAR(1000) SET @string = 'a,b,c,d ,' SELECT LEN(@string) - LEN(REPLACE(@string, ',', ''))по какой-то причине REPLACE избавляется от последней запятой, но также и от пространства перед ней (не знаю, почему). Это приводит к возвращенному значению 5, Когда вы ожидаете 4. Вот еще один способ сделать это, который будет работать даже в этом особом случае:
DECLARE @string VARCHAR(1000) SET @string = 'a,b,c,d ,' SELECT LEN(REPLACE(@string, ',', '**')) - LEN(@string)обратите внимание, что вам не нужно использовать звездочки. Подойдет любая двухсимвольная замена. Идея заключается в том, что вы удлиняете строку на один символ для каждого экземпляра символа, который вы подсчитываете, а затем вычитаете длину оригинала. Это в основном противоположный метод оригинального ответа, который не приходит со странным побочным эффектом обрезки.
Declare @string varchar(1000) DECLARE @SearchString varchar(100) Set @string = 'as as df df as as as' SET @SearchString = 'as' select ((len(@string) - len(replace(@string, @SearchString, ''))) -(len(@string) - len(replace(@string, @SearchString, ''))) % 2) / len(@SearchString)
основываясь на решении @Andrew, вы получите гораздо лучшую производительность, используя непроцедурную табличную функцию и перекрестное применение:
SET ANSI_NULLS ON GO SET QUOTED_IDENTIFIER ON GO /* Usage: SELECT t.[YourColumn], c.StringCount FROM YourDatabase.dbo.YourTable t CROSS APPLY dbo.CountOccurrencesOfString('your search string', t.[YourColumn]) c */ CREATE FUNCTION [dbo].[CountOccurrencesOfString] ( @searchTerm nvarchar(max), @searchString nvarchar(max) ) RETURNS TABLE AS RETURN SELECT (DATALENGTH(@searchString)-DATALENGTH(REPLACE(@searchString,@searchTerm,'')))/NULLIF(DATALENGTH(@searchTerm), 0) AS StringCount
принятый ответ правильный , расширение его для использования 2 или более символов в подстроке:
Declare @string varchar(1000) Set @string = 'aa,bb,cc,dd' Set @substring = 'aa' select (len(@string) - len(replace(@string, @substring, '')))/len(@substring)
DECLARE @records varchar(400) SELECT @records = 'a,b,c,d' select LEN(@records) as 'Before removing Commas' , LEN(@records) - LEN(REPLACE(@records, ',', '')) 'After Removing Commans'
Даррел ли, я думаю, имеет довольно хороший ответ. Заменить
CHARINDEX()СPATINDEX(), и вы можете сделать некоторые слабыеregexпоиск по строке тоже...похоже, что вы используете это для
@pattern:set @pattern='%[-.|!,'+char(9)+']%'почему вы, возможно, хотите сделать что-то сумасшедшее, как это?
скажем, вы загружаете разделенные текстовые строки в промежуточную таблицу, где поле, содержащее данные, является чем-то вроде varchar(8000) или nvarchar(max)...
иногда проще / быстрее выполнять ELT (Extract-Load-Transform) с данными, а не ETL (Extract-Transform-Load), и один из способов сделать это-загрузить разделенные записи как есть в промежуточную таблицу, особенно если вам может понадобиться более простой способ увидеть исключительные записи, а не обрабатывать их как часть пакета служб SSIS...но это священная война за другую нить.
следующее должно сделать трюк как для одного символа, так и для нескольких символов поиска:
CREATE FUNCTION dbo.CountOccurrences ( @SearchString VARCHAR(1000), @SearchFor VARCHAR(1000) ) RETURNS TABLE AS RETURN ( SELECT COUNT(*) AS Occurrences FROM ( SELECT ROW_NUMBER() OVER (ORDER BY O.object_id) AS n FROM sys.objects AS O ) AS N JOIN ( VALUES (@SearchString) ) AS S (SearchString) ON SUBSTRING(S.SearchString, N.n, LEN(@SearchFor)) = @SearchFor ); GO --------------------------------------------------------------------------------------- -- Test the function for single and multiple character searches --------------------------------------------------------------------------------------- DECLARE @SearchForComma VARCHAR(10) = ',', @SearchForCharacters VARCHAR(10) = 'de'; DECLARE @TestTable TABLE ( TestData VARCHAR(30) NOT NULL ); INSERT INTO @TestTable ( TestData ) VALUES ('a,b,c,de,de ,d e'), ('abc,de,hijk,,'), (',,a,b,cde,,'); SELECT TT.TestData, CO.Occurrences AS CommaOccurrences, CO2.Occurrences AS CharacterOccurrences FROM @TestTable AS TT OUTER APPLY dbo.CountOccurrences(TT.TestData, @SearchForComma) AS CO OUTER APPLY dbo.CountOccurrences(TT.TestData, @SearchForCharacters) AS CO2;функция может быть упрощена немного с помощью таблицы чисел (dbo.Nums):
RETURN ( SELECT COUNT(*) AS Occurrences FROM dbo.Nums AS N JOIN ( VALUES (@SearchString) ) AS S (SearchString) ON SUBSTRING(S.SearchString, N.n, LEN(@SearchFor)) = @SearchFor );
Если мы знаем, что есть ограничение на LEN и пространство, почему мы не можем сначала заменить пространство? Тогда мы знаем, что нет места, чтобы запутать Лена.
len(replace(@string, ' ', '-')) - len(replace(replace(@string, ' ', '-'), ',', ''))
используйте этот код, он отлично работает. Я создал функцию sql, которая принимает два параметра, первый параметр-это длинная строка,которую мы хотим найти в ней, и она может принимать длину строки до 1500 символов(конечно, вы можете расширить ее или даже изменить ее на текстовый тип данных). И второй параметр-это подстрока, которую мы хотим вычислить по количеству ее появления (ее длина до 200 символов, конечно, вы можете изменить ее на то, что вам нужно). а выходными данными - целое число, представляет собой число частоты.....наслаждаться этим.
CREATE FUNCTION [dbo].[GetSubstringCount] ( @InputString nvarchar(1500), @SubString NVARCHAR(200) ) RETURNS int AS BEGIN declare @K int , @StrLen int , @Count int , @SubStrLen int set @SubStrLen = (select len(@SubString)) set @Count = 0 Set @k = 1 set @StrLen =(select len(@InputString)) While @K <= @StrLen Begin if ((select substring(@InputString, @K, @SubStrLen)) = @SubString) begin if ((select CHARINDEX(@SubString ,@InputString)) > 0) begin set @Count = @Count +1 end end Set @K=@k+1 end return @Count end
Я, наконец, пишу эту функцию,которая должна охватывать все возможные ситуации, добавляя префикс char и суффикс на вход. этот символ оценивается как отличный от любого из символов, содержащихся в параметре поиска, поэтому он не может повлиять на результат.
CREATE FUNCTION [dbo].[CountOccurrency] ( @Input nvarchar(max), @Search nvarchar(max) ) RETURNS int AS BEGIN declare @SearhLength as int = len('-' + @Search + '-') -2; declare @conteinerIndex as int = 255; declare @conteiner as char(1) = char(@conteinerIndex); WHILE ((CHARINDEX(@conteiner, @Search)>0) and (@conteinerIndex>0)) BEGIN set @conteinerIndex = @conteinerIndex-1; set @conteiner = char(@conteinerIndex); END; set @Input = @conteiner + @Input + @conteiner RETURN (len(@Input) - len(replace(@Input, @Search, ''))) / @SearhLength ENDиспользование
select dbo.CountOccurrency('a,b,c,d ,', ',')
для извлечения значений можно использовать следующую хранимую процедуру.
IF EXISTS (SELECT * FROM sys.objects WHERE object_id = OBJECT_ID(N'[dbo].[sp_parsedata]') AND type in (N'P', N'PC')) DROP PROCEDURE [dbo].[sp_parsedata] GO create procedure sp_parsedata (@cid integer,@st varchar(1000)) as declare @coid integer declare @c integer declare @c1 integer select @c1=len(@st) - len(replace(@st, ',', '')) set @c=0 delete from table1 where complainid=@cid; while (@c<=@c1) begin if (@c<@c1) begin select @coid=cast(replace(left(@st,CHARINDEX(',',@st,1)),',','') as integer) select @st=SUBSTRING(@st,CHARINDEX(',',@st,1)+1,LEN(@st)) end else begin select @coid=cast(@st as integer) end insert into table1(complainid,courtid) values(@cid,@coid) set @c=@c+1 end
тест Replace/Len симпатичен, но, вероятно, очень неэффективен (особенно с точки зрения памяти). Простая функция с петлей будет делать эту работу.
CREATE FUNCTION [dbo].[fn_Occurences] ( @pattern varchar(255), @expression varchar(max) ) RETURNS int AS BEGIN DECLARE @Result int = 0; DECLARE @index BigInt = 0 DECLARE @patLen int = len(@pattern) SET @index = CHARINDEX(@pattern, @expression, @index) While @index > 0 BEGIN SET @Result = @Result + 1; SET @index = CHARINDEX(@pattern, @expression, @index + @patLen) END RETURN @Result END
возможно, вы не должны хранить данные таким образом. Это плохая практика, чтобы когда-либо хранить список с разделителями-запятыми в поле. Это очень неэффективно для запроса. Это должна быть связанная таблица.
Comments