Ben a, b, c, d gibi biçimlendirilmiş değerleri olan bir sütun var. T-SQL'de bu değerdeki virgül sayısını saymanın bir yolu var mı?
Ben a, b, c, d gibi biçimlendirilmiş değerleri olan bir sütun var. T-SQL'de bu değerdeki virgül sayısını saymanın bir yolu var mı?
Yanıtlar:
Akla gelen ilk yol, boş bir dize ile virgül değiştirerek ve uzunlukları karşılaştırarak dolaylı olarak yapmaktır.
Declare @string varchar(1000)
Set @string = 'a,b,c,d'
select len(@string) - len(replace(@string, ',', ''))
LTRIM
aşağıdaki gibi dize etrafında: SELECT LEN(RTRIM(@string)) - LEN(REPLACE(RTRIM(@string), ',', ''))
?
Daha fazla karakter dizeleri için çalışan cmsjr cevabının hızlı uzantısı.
CREATE FUNCTION dbo.CountOccurrencesOfString
(
@searchString nvarchar(max),
@searchTerm nvarchar(max)
)
RETURNS INT
AS
BEGIN
return (LEN(@searchString)-LEN(REPLACE(@searchString,@searchTerm,'')))/LEN(@searchTerm)
END
Kullanımı:
SELECT * FROM MyTable
where dbo.CountOccurrencesOfString(MyColumn, 'MyString') = 1
dbo.CountOccurancesOfString( 'blah ,', ',')
1 yerine 2 döndürür ve dbo.CountOccurancesOfString( 'hello world', ' ')
sıfıra bölme başarısız olur.
DATALENGTH()/2
Ayrıca, belirgin olmayan karakter boyutları nedeniyle de zor. Basit ve doğru bir yol için stackoverflow.com/a/11080074/1094048 adresine bakın .
@ Andrew'un çözümünü temel alarak, işlemsel olmayan tablo değerli bir işlev ve CROSS UYGULAMA kullanarak çok daha iyi performans elde edersiniz:
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 tarafından verilen yanıtın bazı durumlarda bir sorunu vardır.
Cevabı bunu yapmaktı:
Declare @string varchar(1000)
Set @string = 'a,b,c,d'
select len(@string) - len(replace(@string, ',', ''))
Bu, çoğu senaryoda çalışır, ancak şunu çalıştırmayı deneyin:
DECLARE @string VARCHAR(1000)
SET @string = 'a,b,c,d ,'
SELECT LEN(@string) - LEN(REPLACE(@string, ',', ''))
Bazı nedenlerden dolayı, REPLACE son virgülden kurtulur, ancak AYRICA hemen önündeki boşluk (neden olduğundan emin değilsiniz). Bu, 4'ü beklediğinizde 5 değerini döndürür. Bu, bu özel senaryoda bile çalışacak başka bir yöntemdir:
DECLARE @string VARCHAR(1000)
SET @string = 'a,b,c,d ,'
SELECT LEN(REPLACE(@string, ',', '**')) - LEN(@string)
Yıldız işareti kullanmanıza gerek olmadığını unutmayın. Herhangi iki karakterli değiştirme yapılır. Fikir, dizeyi saydığınız karakterin her bir örneği için bir karakter uzatmanız ve ardından orijinalin uzunluğunu çıkarmanızdır. Temel olarak, orijinal cevabın garip kırpma yan etkisi ile gelmeyen zıt yöntemidir.
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)
Kabul edilen cevap doğrudur ve alt dize içinde 2 veya daha fazla karakter kullanacak şekilde genişletilir:
Declare @string varchar(1000)
Set @string = 'aa,bb,cc,dd'
Set @substring = 'aa'
select (len(@string) - len(replace(@string, @substring, '')))/len(@substring)
Darrel Lee Bence oldukça iyi bir cevabı var. Değiştir CHARINDEX()
ile PATINDEX()
ve bazı zayıf yapabilirsiniz regex
de bir dize boyunca arama ...
Diyelim ki şunu kullanıyorsunuz @pattern
:
set @pattern='%[-.|!,'+char(9)+']%'
Neden böyle çılgınca bir şey yapmak istesin?
Sınırlı metin dizelerini, verileri tutan alanın varchar (8000) veya nvarchar (max) gibi bir şey olduğu bir hazırlama tablosuna yüklediğinizi varsayalım ...
Bazen ETL (Extract-Transform-Load) yerine verilerle ELT (Extract-Load-Transform) yapmak daha kolay / hızlıdır ve bunu yapmanın bir yolu, sınırlandırılmış kayıtları olduğu gibi bir hazırlama tablosuna olduğu gibi yüklemek, özellikle de bir SSIS paketinin parçası olarak onlarla uğraşmak yerine istisnai kayıtları görmenin daha basit bir yolunu isteyebilirsiniz ... ama bu farklı bir iş parçacığı için kutsal bir savaş.
Aşağıdakiler, hem tek karakter hem de çoklu karakter aramaları için hile yapmalıdır:
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;
Bir sayı tablosu (dbo.Nums) kullanılarak işlev biraz basitleştirilebilir:
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
);
Bu kodu kullanın, mükemmel çalışıyor. İki parametre kabul eden bir sql işlevi var, ilk param içine aramak istediğimiz uzun dizedir ve 1500 karaktere kadar dize uzunluğunu kabul edebilir (tabii ki genişletebilir veya hatta metin veri tipine değiştirebilirsiniz) ). Ve ikinci parametre, meydana gelme sayısını hesaplamak istediğimiz alt dizedir (uzunluğu 200 karaktere kadardır, elbette bunu ihtiyacınıza göre değiştirebilirsiniz). ve çıkış bir tamsayı, frekans sayısını temsil ..... zevk.
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
Son olarak, girdiye bir char öneki ve son ek ekleyerek tüm olası durumları kapsaması gereken bu işlevi yazıyorum. bu karakter, arama parametresinde bulunan karakterlerden farklı olarak değerlendirilir, dolayısıyla sonucu etkileyemez.
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
kullanım
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 veya daha yeni sürümlerde şunları kullanabilirsiniz:
declare @hits int = 0
set @hits = (select value from STRING_SPLIT('F609,4DFA,8499',','));
select count(@hits)
bu T-SQL kodu cümlesindeki @ paterninin tüm örneklerini bulur ve yazdırır. daha sonra cümle üzerinde herhangi bir işlem yapabilirsiniz.
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
sonuç: 1 6 13 20
SQL Server 2017 için
declare @hits int = 0;
set @hits = (select count(*) from (select value from STRING_SPLIT('F609,4DFA,8499',',')) a);
select @hits;
Değerleri almak için aşağıdaki saklı yordamı kullanabilirsiniz.
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
istediği cevaba ayarlanır . Kodun geri kalanı, table1
çalışmak için önceden var olan bir tabloya ihtiyaç duyduğu , sabit kodlu bir sınırlayıcıya sahip olduğu ve iki ay önceki kabul edilen cevap gibi satır içi kullanılamayacağı düşünüldüğünde ne işe yarar ?
Replace / Len testi sevimli, ama muhtemelen çok verimsiz (özellikle bellek açısından). Bir döngü ile basit bir işlev işi yapar.
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
Belki de verileri bu şekilde depolamamalısınız. Bir alanda virgülle ayrılmış bir listeyi saklamak kötü bir uygulamadır. BT sorgulama için çok verimsiz. Bu ilgili bir tablo olmalıdır.