У мене стовпець із значеннями, відформатованими як a, b, c, d. Чи є спосіб підрахувати кількість коми в цьому значенні в T-SQL?
У мене стовпець із значеннями, відформатованими як a, b, c, d. Чи є спосіб підрахувати кількість коми в цьому значенні в T-SQL?
Відповіді:
Перший спосіб, який спадає на думку, - це зробити це опосередковано, замінивши кому на порожню рядок і порівнявши довжини
Declare @string varchar(1000)
Set @string = 'a,b,c,d'
select len(@string) - len(replace(@string, ',', ''))
LTRIM
навколо рядка так SELECT LEN(RTRIM(@string)) - LEN(REPLACE(RTRIM(@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
dbo.CountOccurancesOfString( 'blah ,', ',')
поверне 2 замість 1 і dbo.CountOccurancesOfString( 'hello world', ' ')
не зможе ділитися на нуль.
DATALENGTH()/2
також складний через неочевидних розмірів діаграм. Подивіться на stackoverflow.com/a/11080074/1094048 для простого і точного способу.
Спираючись на рішення Ендрю, ви отримаєте набагато кращі показники, використовуючи непроцедурну функцію табличного значення та CROSS APPLY:
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
У відповіді @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)
Прийнята відповідь є правильною, розширивши її на використання 2 або більше символів у підрядках:
Declare @string varchar(1000)
Set @string = 'aa,bb,cc,dd'
Set @substring = 'aa'
select (len(@string) - len(replace(@string, @substring, '')))/len(@substring)
Даррел Лі, я думаю, має досить гарну відповідь. Замініть 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
);
Використовуйте цей код, він працює чудово. Я створив функцію 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 ,', ',')
Declare @MainStr nvarchar(200)
Declare @SubStr nvarchar(10)
Set @MainStr = 'nikhildfdfdfuzxsznikhilweszxnikhil'
Set @SubStr = 'nikhil'
Select (Len(@MainStr) - Len(REPLACE(@MainStr,@SubStr,'')))/Len(@SubStr)
У SQL 2017 або новіших версіях ви можете використовувати це:
declare @hits int = 0
set @hits = (select value from STRING_SPLIT('F609,4DFA,8499',','));
select count(@hits)
цей код T-SQL знаходить і друкує всі виникнення шаблону @p у реченні @s. Ви можете зробити будь-яку обробку речення згодом.
declare @old_hit int = 0
declare @hit int = 0
declare @i int = 0
declare @s varchar(max)='alibcalirezaalivisualization'
declare @p varchar(max)='ali'
while @i<len(@s)
begin
set @hit=charindex(@p,@s,@i)
if @hit>@old_hit
begin
set @old_hit =@hit
set @i=@hit+1
print @hit
end
else
break
end
результат: 1 6 13 20
для SQL Server 2017
declare @hits int = 0;
set @hits = (select count(*) from (select value from STRING_SPLIT('F609,4DFA,8499',',')) a);
select @hits;
Ви можете використовувати наступну збережену процедуру для отримання значень.
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
@c1
відповідає відповіді, яку він вимагає. Яке використання решти коду, враховуючи, що для цього потрібна попередньо існуюча таблиця, викликана table1
для роботи, має жорсткий кодовий деліметр і не може бути використана в рядку, як прийнятий відповідь за два місяці до цього?
Тест 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
Можливо, ви не повинні зберігати дані таким чином. Погана практика коли-небудь зберігати список з обмеженими комами в полі. ІТ дуже неефективний для запитів. Це має бути пов'язана таблиця.