Ich habe eine Spalte mit Werten, die wie a, b, c, d formatiert sind. Gibt es eine Möglichkeit, die Anzahl der Kommas in diesem Wert in T-SQL zu zählen?
Ich habe eine Spalte mit Werten, die wie a, b, c, d formatiert sind. Gibt es eine Möglichkeit, die Anzahl der Kommas in diesem Wert in T-SQL zu zählen?
Antworten:
Der erste Weg, der mir in den Sinn kommt, besteht darin, dies indirekt zu tun, indem das Komma durch eine leere Zeichenfolge ersetzt und die Längen verglichen werden
Declare @string varchar(1000)
Set @string = 'a,b,c,d'
select len(@string) - len(replace(@string, ',', ''))
LTRIM
wie folgt um die Zeichenfolge wickeln : SELECT LEN(RTRIM(@string)) - LEN(REPLACE(RTRIM(@string), ',', ''))
?
Schnelle Erweiterung der Antwort von cmsjr, die für Zeichenfolgen mit mehr als mehr Zeichen funktioniert.
CREATE FUNCTION dbo.CountOccurrencesOfString
(
@searchString nvarchar(max),
@searchTerm nvarchar(max)
)
RETURNS INT
AS
BEGIN
return (LEN(@searchString)-LEN(REPLACE(@searchString,@searchTerm,'')))/LEN(@searchTerm)
END
Verwendung:
SELECT * FROM MyTable
where dbo.CountOccurrencesOfString(MyColumn, 'MyString') = 1
dbo.CountOccurancesOfString( 'blah ,', ',')
2 anstelle von 1 zurück und dbo.CountOccurancesOfString( 'hello world', ' ')
schlägt mit der Division durch Null fehl.
DATALENGTH()/2
ist auch wegen nicht offensichtlicher Zeichengrößen schwierig. Unter stackoverflow.com/a/11080074/1094048 finden Sie eine einfache und genaue Möglichkeit.
Aufbauend auf der Lösung von @ Andrew erhalten Sie eine viel bessere Leistung, wenn Sie eine nicht prozedurale Tabellenwertfunktion und CROSS APPLY verwenden:
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
Die Antwort von @csmjr hat in einigen Fällen ein Problem.
Seine Antwort war:
Declare @string varchar(1000)
Set @string = 'a,b,c,d'
select len(@string) - len(replace(@string, ',', ''))
Dies funktioniert in den meisten Szenarien. Versuchen Sie jedoch Folgendes:
DECLARE @string VARCHAR(1000)
SET @string = 'a,b,c,d ,'
SELECT LEN(@string) - LEN(REPLACE(@string, ',', ''))
Aus irgendeinem Grund entfernt REPLACE das letzte Komma, aber AUCH das Leerzeichen davor (nicht sicher warum). Dies führt zu einem zurückgegebenen Wert von 5, wenn Sie 4 erwarten würden. Hier ist eine andere Möglichkeit, die auch in diesem speziellen Szenario funktioniert:
DECLARE @string VARCHAR(1000)
SET @string = 'a,b,c,d ,'
SELECT LEN(REPLACE(@string, ',', '**')) - LEN(@string)
Beachten Sie, dass Sie keine Sternchen verwenden müssen. Jeder Ersatz durch zwei Zeichen reicht aus. Die Idee ist, dass Sie die Zeichenfolge für jede Instanz des Zeichens, das Sie zählen, um ein Zeichen verlängern und dann die Länge des Originals subtrahieren. Es ist im Grunde die entgegengesetzte Methode der ursprünglichen Antwort, die nicht mit dem seltsamen Nebeneffekt des Trimmens einhergeht.
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)
Die akzeptierte Antwort ist korrekt und erweitert sie auf die Verwendung von 2 oder mehr Zeichen in der Teilzeichenfolge:
Declare @string varchar(1000)
Set @string = 'aa,bb,cc,dd'
Set @substring = 'aa'
select (len(@string) - len(replace(@string, @substring, '')))/len(@substring)
Darrel Lee hat meiner Meinung nach eine ziemlich gute Antwort. Ersetzen Sie CHARINDEX()
durch PATINDEX()
, und Sie können auch regex
entlang einer Zeichenfolge schwach suchen ...
Angenommen, Sie verwenden dies für @pattern
:
set @pattern='%[-.|!,'+char(9)+']%'
Warum willst du vielleicht so etwas Verrücktes machen?
Angenommen, Sie laden begrenzte Textzeichenfolgen in eine Staging-Tabelle, in der das Feld, in dem sich die Daten befinden, so etwas wie ein Varchar (8000) oder ein Nvarchar (max) ist.
Manchmal ist es einfacher / schneller, ELT (Extract-Load-Transform) mit Daten anstelle von ETL (Extract-Transform-Load) durchzuführen, und eine Möglichkeit, dies zu tun, besteht darin, die begrenzten Datensätze unverändert in eine Staging-Tabelle zu laden, insbesondere wenn Vielleicht möchten Sie die außergewöhnlichen Datensätze einfacher anzeigen, als sie als Teil eines SSIS-Pakets zu behandeln ... aber das ist ein heiliger Krieg für einen anderen Thread.
Folgendes sollte den Trick sowohl für die Suche nach einzelnen als auch nach mehreren Zeichen ausführen:
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;
Die Funktion kann mithilfe einer Zahlentabelle (dbo.Nums) etwas vereinfacht werden:
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
);
Verwenden Sie diesen Code, es funktioniert einwandfrei. Ich habe eine SQL-Funktion erstellt, die zwei Parameter akzeptiert. Der erste Parameter ist die lange Zeichenfolge, nach der gesucht werden soll, und sie kann eine Zeichenfolgenlänge von bis zu 1500 Zeichen akzeptieren (natürlich können Sie sie erweitern oder sogar in einen Textdatentyp ändern ). Und der zweite Parameter ist der Teilstring, mit dem wir die Anzahl seiner Vorkommen berechnen möchten (seine Länge beträgt bis zu 200 Zeichen, natürlich können Sie ihn nach Ihren Wünschen ändern). und die Ausgabe ist eine ganze Zahl, repräsentieren die Anzahl der Frequenzen ..... genießen Sie es.
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
Ich schreibe schließlich diese Funktion, die alle möglichen Situationen abdecken soll, indem ich der Eingabe ein Zeichenpräfix und ein Suffix hinzufüge. Dieses Zeichen unterscheidet sich von dem im Suchparameter enthaltenen Zeichen und kann daher das Ergebnis nicht beeinflussen.
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
Verwendung
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)
In SQL 2017 oder höher können Sie Folgendes verwenden:
declare @hits int = 0
set @hits = (select value from STRING_SPLIT('F609,4DFA,8499',','));
select count(@hits)
Dieser T-SQL-Code findet und druckt alle Vorkommen von Muster @p in Satz @s. Sie können den Satz anschließend beliebig bearbeiten.
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
das Ergebnis ist: 1 6 13 20
für SQL Server 2017
declare @hits int = 0;
set @hits = (select count(*) from (select value from STRING_SPLIT('F609,4DFA,8499',',')) a);
select @hits;
Sie können die folgende gespeicherte Prozedur verwenden, um Werte abzurufen.
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
auf die Antwort, die er benötigt. Was nützt der Rest des Codes, wenn man bedenkt, dass er eine bereits vorhandene Tabelle benötigt, um table1
zu funktionieren, einen fest codierten Begrenzer hat und nicht wie die akzeptierte Antwort von zwei Monaten zuvor inline verwendet werden kann?
Der Replace / Len-Test ist niedlich, aber wahrscheinlich sehr ineffizient (insbesondere in Bezug auf den Speicher). Eine einfache Funktion mit einer Schleife erledigt den Job.
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
Vielleicht sollten Sie Daten nicht so speichern. Es ist eine schlechte Praxis, jemals eine durch Kommas getrennte Liste in einem Feld zu speichern. IT ist für die Abfrage sehr ineffizient. Dies sollte eine verwandte Tabelle sein.