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 ,', ',')
、1ではなく2を返しdbo.CountOccurancesOfString( 'hello world', ' ')
、ゼロ除算で失敗します。
DATALENGTH()/2
文字サイズがわかりにくいため、注意も必要です。シンプルで正確な方法については、stackoverflow.com / a / 11080074/1094048をご覧ください。
@Andrewのソリューションを基に、非手続き型のテーブル値関数と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は最後のコンマを削除しますが、その直前のスペースも(理由は不明です)。これにより、4を期待する場合に戻り値は5になります。これは、この特別なシナリオでも機能する別の方法です。
DECLARE @string VARCHAR(1000)
SET @string = 'a,b,c,d ,'
SELECT LEN(REPLACE(@string, ',', '**')) - LEN(@string)
アスタリスクを使用する必要がないことに注意してください。2文字の置換で十分です。カウントする文字のインスタンスごとに文字列を1文字ずつ長くしてから、元の長さを引くという考え方です。それは基本的に、奇妙なトリミングの副作用を伴わない元の答えの反対の方法です。
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)
ダレル・リーかなり良い答えがあると思います。交換するCHARINDEX()
とPATINDEX()
、あなたは、いくつかの弱い行うことができますregex
あまりにも、文字列に沿って検索を...
たとえば、これを次の目的で使用するとします@pattern
。
set @pattern='%[-.|!,'+char(9)+']%'
なぜあなたはこのようにクレイジーなことをしたいのですか?
データを保持するフィールドがvarchar(8000)やnvarchar(max)などのステージングテーブルに区切られたテキスト文字列をロードしているとします...
ETL(Extract-Transform-Load)よりもデータでELT(Extract-Load-Transform)を実行する方が簡単/高速である場合があります。これを行う1つの方法は、区切られたレコードをそのままステージングテーブルにロードすることです。例外的なレコードを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
);
このコードを使用すると、完全に機能します。2つのパラメーターを受け入れるSQL関数を作成しました。最初のパラメーターは、検索する長い文字列であり、最大1500文字の文字列を受け入れることができます(もちろん、拡張したり、テキストデータ型に変更したりすることもできます) )。そして、2番目のパラメーターは、その出現回数を計算する部分文字列です(長さは最大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 ,', ',')
このT-SQLコードは、文@s内のパターン@pのすべての出現を検出して出力します。その後、文に対して任意の処理を行うことができます。
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
であり、ハードコードされたデリミタがあり、2か月前から受け入れられた回答のようにインラインで使用できないことを考えると、残りのコードはどのように使用されますか?
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
おそらく、そのようにデータを保存するべきではありません。カンマ区切りのリストをフィールドに格納することは悪い習慣です。ITはクエリに対して非常に非効率的です。これは関連テーブルでなければなりません。