Câu trả lời:
Cách đầu tiên bạn nghĩ đến là làm điều đó một cách gián tiếp bằng cách thay thế dấu phẩy bằng một chuỗi rỗng và so sánh độ dài
Declare @string varchar(1000)
Set @string = 'a,b,c,d'
select len(@string) - len(replace(@string, ',', ''))
LTRIM
chuỗi xung quanh như sau : SELECT LEN(RTRIM(@string)) - LEN(REPLACE(RTRIM(@string), ',', ''))
?
Mở rộng nhanh câu trả lời của cmsjr hoạt động cho các chuỗi có nhiều ký tự hơn.
CREATE FUNCTION dbo.CountOccurrencesOfString
(
@searchString nvarchar(max),
@searchTerm nvarchar(max)
)
RETURNS INT
AS
BEGIN
return (LEN(@searchString)-LEN(REPLACE(@searchString,@searchTerm,'')))/LEN(@searchTerm)
END
Sử dụng:
SELECT * FROM MyTable
where dbo.CountOccurrencesOfString(MyColumn, 'MyString') = 1
dbo.CountOccurancesOfString( 'blah ,', ',')
sẽ trả về 2 thay vì 1 và dbo.CountOccurancesOfString( 'hello world', ' ')
sẽ thất bại với phép chia cho 0.
DATALENGTH()/2
cũng khó khăn vì kích thước char không rõ ràng. Nhìn vào stackoverflow.com/a/11080074/1094048 để biết cách đơn giản và chính xác.
Dựa trên giải pháp của @ Andrew, bạn sẽ có hiệu suất tốt hơn nhiều khi sử dụng hàm không có giá trị của bảng theo thủ tục và ỨNG DỤNG CROSS:
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
Câu trả lời của @csmjr có vấn đề trong một số trường hợp.
Câu trả lời của ông là làm điều này:
Declare @string varchar(1000)
Set @string = 'a,b,c,d'
select len(@string) - len(replace(@string, ',', ''))
Điều này hoạt động trong hầu hết các kịch bản, tuy nhiên, hãy thử chạy này:
DECLARE @string VARCHAR(1000)
SET @string = 'a,b,c,d ,'
SELECT LEN(@string) - LEN(REPLACE(@string, ',', ''))
Vì một số lý do, REPLACE thoát khỏi dấu phẩy cuối cùng nhưng CSONG không gian ngay trước nó (không chắc tại sao). Điều này dẫn đến giá trị trả về là 5 khi bạn mong đợi 4. Đây là một cách khác để làm điều này sẽ hoạt động ngay cả trong kịch bản đặc biệt này:
DECLARE @string VARCHAR(1000)
SET @string = 'a,b,c,d ,'
SELECT LEN(REPLACE(@string, ',', '**')) - LEN(@string)
Lưu ý rằng bạn không cần sử dụng dấu sao. Bất kỳ thay thế hai ký tự sẽ làm. Ý tưởng là bạn kéo dài chuỗi bằng một ký tự cho mỗi phiên bản của ký tự bạn đang đếm, sau đó trừ đi độ dài của bản gốc. Về cơ bản, đây là phương pháp ngược lại với câu trả lời ban đầu không đi kèm với hiệu ứng phụ cắt tỉa kỳ lạ.
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)
Câu trả lời được chấp nhận là chính xác, mở rộng nó để sử dụng 2 hoặc nhiều ký tự trong chuỗi con:
Declare @string varchar(1000)
Set @string = 'aa,bb,cc,dd'
Set @substring = 'aa'
select (len(@string) - len(replace(@string, @substring, '')))/len(@substring)
Darrel Lee tôi nghĩ rằng có một câu trả lời khá tốt. Thay thế CHARINDEX()
bằng PATINDEX()
và bạn cũng có thể thực hiện một số regex
tìm kiếm yếu dọc theo chuỗi, ...
Giống như, nói rằng bạn sử dụng điều này cho @pattern
:
set @pattern='%[-.|!,'+char(9)+']%'
Tại sao bạn có thể muốn làm một cái gì đó điên rồ như thế này?
Giả sử bạn đang tải các chuỗi văn bản được phân tách vào một bảng phân tầng, trong đó trường chứa dữ liệu giống như một varchar (8000) hoặc nvarchar (max) ...
Đôi khi, thực hiện ELT (Extract-Load-Transform) với dữ liệu thay vì ETL (Extract-Transform-Load) dễ dàng hơn và nhanh hơn, và một cách để làm điều này là tải các bản ghi được phân tách như trong bảng phân tầng, đặc biệt là bạn có thể muốn một cách đơn giản hơn để xem các bản ghi đặc biệt thay vì xử lý chúng như một phần của gói SSIS ... nhưng đó là một cuộc chiến thần thánh cho một chủ đề khác.
Sau đây nên thực hiện thủ thuật cho cả tìm kiếm một ký tự và nhiều ký tự:
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;
Hàm có thể được đơn giản hóa một chút bằng cách sử dụng bảng số (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
);
Sử dụng mã này, nó đang hoạt động hoàn hảo. Tôi đã tạo một hàm sql chấp nhận hai tham số, tham số đầu tiên là chuỗi dài mà chúng ta muốn tìm kiếm và nó có thể chấp nhận độ dài chuỗi lên tới 1500 ký tự (tất nhiên bạn có thể mở rộng nó hoặc thậm chí thay đổi nó thành kiểu dữ liệu văn bản ). Và tham số thứ hai là chuỗi con mà chúng tôi muốn tính số lần xuất hiện của nó (độ dài của nó lên tới 200 ký tự, tất nhiên bạn có thể thay đổi nó thành những gì bạn cần). và đầu ra là một số nguyên, biểu thị số tần số ..... thưởng thức nó.
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
Cuối cùng tôi đã viết hàm này sẽ bao gồm tất cả các tình huống có thể, thêm tiền tố char và hậu tố vào đầu vào. char này được đánh giá là khác với bất kỳ char nào được xác định trong tham số tìm kiếm, vì vậy nó không thể ảnh hưởng đến kết quả.
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
sử dụng
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)
Trong SQL 2017 trở lên, bạn có thể sử dụng điều này:
declare @hits int = 0
set @hits = (select value from STRING_SPLIT('F609,4DFA,8499',','));
select count(@hits)
mã T-SQL này tìm và in tất cả các lần xuất hiện của mẫu @p trong câu @s. bạn có thể thực hiện bất kỳ xử lý trên câu sau đó.
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
kết quả là: 1 6 13 20
cho SQL Server 2017
declare @hits int = 0;
set @hits = (select count(*) from (select value from STRING_SPLIT('F609,4DFA,8499',',')) a);
select @hits;
Bạn có thể sử dụng các thủ tục được lưu trữ sau đây để tìm nạp, các giá trị.
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
ra câu trả lời mà anh ta yêu cầu. Việc sử dụng là phần còn lại của mã, xem xét rằng nó cần một bảng có sẵn được gọi table1
để làm việc, có một phân tách mã hóa cứng và không thể được sử dụng nội tuyến như câu trả lời được chấp nhận từ hai tháng trước?
Bài kiểm tra Thay thế / Len rất dễ thương, nhưng có lẽ rất kém hiệu quả (đặc biệt là về bộ nhớ). Một chức năng đơn giản với một vòng lặp sẽ thực hiện công việc.
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
Có lẽ bạn không nên lưu trữ dữ liệu theo cách đó. Đó là một thực tế xấu khi lưu trữ một danh sách được phân cách bằng dấu phẩy trong một trường. CNTT rất không hiệu quả để truy vấn. Đây phải là một bảng liên quan.