आप SQL varchar में एक निश्चित सबस्ट्रिंग की घटनाओं की संख्या कैसे गिनते हैं?


150

मेरे पास एक कॉलम है जिसमें मानों को a, b, c, d जैसे स्वरूपित किया गया है। टी-एसक्यूएल में उस मूल्य में अल्पविराम की संख्या को गिनने का कोई तरीका है?

जवाबों:


245

पहला तरीका जो मन में आता है वह है अप्रत्यक्ष रूप से अल्पविराम की जगह खाली स्ट्रिंग और लंबाई की तुलना करके।

Declare @string varchar(1000)
Set @string = 'a,b,c,d'
select len(@string) - len(replace(@string, ',', ''))

13
जो पाठ में लिखे गए प्रश्न का उत्तर देता है, लेकिन शीर्षक में नहीं लिखा गया है। इसे एक से अधिक वर्णों के लिए काम करने के लिए, बस चीज़ को गोल करने के लिए / लेन (खोजकर्ता) जोड़ना होगा। किसी के लिए उपयोगी है, इस मामले में एक उत्तर दिया।
एंड्रयू बैरेट 25'10

किसी ने मुझे बताया कि यह हमेशा अपेक्षा के अनुरूप काम नहीं करता है। निम्नलिखित पर विचार करें: SELEN LEN ('a, b, c, d,') - LEN (REPLACE ('ए, बी, सी, डी,', ',', ')) उन कारणों के लिए जिन्हें मैं अभी तक नहीं समझता हूं , d और अंतिम कॉलम के बीच का स्थान 4. 4 के बजाय 5 को वापस करने का कारण बनता है। मैं एक और उत्तर पोस्ट करूंगा जो इसे ठीक करता है, यदि यह किसी के लिए उपयोगी है।
बबलिंग

5
हो सकता है कि LEN के बजाय DATALENGTH का उपयोग करना बेहतर होगा, क्योंकि LEN स्ट्रिंग का आकार ट्रिम कर देता है।
रॉडरिग्लोक्

2
DATALENGTH () / 2 गैर-स्पष्ट चार आकारों के कारण भी मुश्किल है। स्ट्रिंग लंबाई पाने के सरल और सटीक तरीके के लिए stackoverflow.com/a/11080074/1094048 पर देखें।
pkuderov

@rodrigocl LTRIMस्ट्रिंग के चारों ओर लपेट क्यों नहीं इस प्रकार है SELECT LEN(RTRIM(@string)) - LEN(REPLACE(RTRIM(@string), ',', '')):?
एलेक्स बेलो

67

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

16
थोड़ा सुधार होगा LEN () के बजाय DATALENGTH () / 2 का उपयोग करना। LEN किसी भी अनुगामी व्हाट्सएप को नजरअंदाज कर dbo.CountOccurancesOfString( 'blah ,', ',')देगा इसलिए 1 के बजाय 2 वापस आ dbo.CountOccurancesOfString( 'hello world', ' ')जाएंगे और शून्य से विभाजित होने में विफल रहेंगे।
रोरी

5
रोरी की टिप्पणी सहायक है। मैंने पाया कि मैं एंड्रयू के फंक्शन में LAT को DATALENGTH से बदल सकता हूं और वांछित परिणाम प्राप्त कर सकता हूं। ऐसा लगता है कि गणित के काम करने के तरीके से 2 को विभाजित करना आवश्यक नहीं है।
गारलैंड पोप

@AndrewBarrett: जब कई तार एक ही लंबाई के हों तो क्या होगा?
user2284570

2
DATALENGTH()/2गैर-स्पष्ट चार आकारों के कारण भी मुश्किल है। सरल और सटीक तरीके के लिए stackoverflow.com/a/11080074/1094048 पर देखें ।
पुकुडरोव

26

आप स्ट्रिंग की लंबाई की तुलना एक के साथ कर सकते हैं जहाँ अल्पविराम हटाए जाते हैं:

len(value) - len(replace(value,',',''))

8

@ एंड्रयू समाधान पर बिल्डिंग, आपको एक गैर-प्रक्रियात्मक तालिका-मूल्यवान-फ़ंक्शन और CROSS APPLYY का उपयोग करके बहुत बेहतर प्रदर्शन मिलेगा:

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

मैं अपने कई विरासत डेटाबेसों में इसी फ़ंक्शन का उपयोग करता हूं, यह बहुत सारे पुराने और अनुचित तरीके से डिज़ाइन किए गए डेटाबेस के साथ एक बड़ा सौदा करने में मदद करता है। समय की एक बड़ी राशि बचाता है और बड़े डेटा सेट पर भी बहुत तेज है।
कैमेन

6

@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 के लौटाए गए मूल्य का परिणाम है। यहाँ ऐसा करने का एक और तरीका है जो इस विशेष परिदृश्य में भी काम करेगा:

DECLARE @string VARCHAR(1000)
SET @string = 'a,b,c,d ,'
SELECT LEN(REPLACE(@string, ',', '**')) - LEN(@string)

ध्यान दें कि आपको तारांकन का उपयोग करने की आवश्यकता नहीं है। कोई भी दो-चरित्र प्रतिस्थापन करेगा। विचार यह है कि आप जिस चरित्र की गिनती कर रहे हैं उसके प्रत्येक उदाहरण के लिए स्ट्रिंग को एक वर्ण से लंबा करते हैं, फिर मूल की लंबाई घटाते हैं। यह मूल रूप से मूल उत्तर की विपरीत विधि है जो अजीब ट्रिमिंग साइड-इफेक्ट के साथ नहीं आती है।


5
"किसी कारण से, REPLACE को अंतिम अल्पविराम से छुटकारा मिल जाता है, लेकिन इसके ठीक पहले का स्थान भी बदल जाता है (निश्चित नहीं क्यों)।" उत्तर अंतिम अल्पविराम और इससे पहले के स्थान से छुटकारा नहीं मिल रहा है, यह वास्तव में LEN फ़ंक्शन है जो उस स्थान के कारण स्ट्रिंग के अंत में होने वाले सफेद-स्थान की अनदेखी कर रहा है।
इमरानुल्लाह खान

2
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)

यह वास्तव में 1 कम वास्तविक गिनती लौटाता है
इंटीग्रेटर

1

स्वीकृत उत्तर सही है, विकल्प में 2 या अधिक वर्ण का उपयोग करने के लिए इसे विस्तारित करना:

Declare @string varchar(1000)
Set @string = 'aa,bb,cc,dd'
Set @substring = 'aa'
select (len(@string) - len(replace(@string, @substring, '')))/len(@substring)

1

अगर हमें पता है कि LEN और स्पेस पर सीमा है, तो हम स्पेस को पहले क्यों नहीं बदल सकते? तब हम जानते हैं कि LEN को भ्रमित करने के लिए कोई जगह नहीं है।

len(replace(@string, ' ', '-')) - len(replace(replace(@string, ' ', '-'), ',', ''))

0
DECLARE @records varchar(400)
SELECT @records = 'a,b,c,d'
select  LEN(@records) as 'Before removing Commas' , LEN(@records) - LEN(REPLACE(@records, ',', '')) 'After Removing Commans'

0

डारेल ली मुझे लगता है कि एक बहुत अच्छा जवाब है। के CHARINDEX()साथ बदलें PATINDEX(), और आप कुछ कमजोर कर सकते हैंregex एक स्ट्रिंग के साथ खोज भी ...

जैसे, आप इसके लिए इसका उपयोग करते हैं @pattern:

set @pattern='%[-.|!,'+char(9)+']%'

आप इस तरह से कुछ पागल क्यों करना चाहेंगे?

मान लें कि आप सीमांकित पाठ स्ट्रिंग्स को एक मेज़िंग तालिका में लोड कर रहे हैं, जहाँ डेटा रखने वाला क्षेत्र कुछ varchar (8000) या nvarchar (अधिकतम) की तरह है ...

कभी-कभी ईटीएल (एक्सट्रैक्ट-ट्रांसफ़ॉर्म-लोड) के बजाय डेटा के साथ ईएलटी (एक्सट्रैक्ट-लोड-ट्रांसफ़ॉर्म) करना आसान / तेज़ होता है, और ऐसा करने का एक तरीका सीमांकित रिकॉर्ड को लोड करना है, जैसे कि एक स्टेजिंग टेबल में, खासकर यदि आप SSIS पैकेज के एक हिस्से के रूप में उनके साथ असाधारण रिकॉर्ड देखने के लिए एक सरल तरीका चाहते हैं ... लेकिन यह एक अलग धागे के लिए एक पवित्र युद्ध है।


0

निम्नलिखित को एकल वर्ण और एकाधिक वर्ण खोज दोनों के लिए चाल करनी चाहिए:

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
          );

0

इस कोड का उपयोग करें, यह पूरी तरह से काम कर रहा है। मैंने एक 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

0

मैं अंत में इस फ़ंक्शन को लिखता हूं जो इनपुट में एक उपसर्ग और प्रत्यय जोड़कर सभी संभावित स्थितियों को कवर करना चाहिए। इस char का मूल्यांकन खोज पैरामीटर में किसी भी char conteined के भिन्न होने के लिए किया जाता है, इसलिए यह परिणाम को प्रभावित नहीं कर सकता है।

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 ,', ',')

0
Declare @MainStr nvarchar(200)
Declare @SubStr nvarchar(10)
Set @MainStr = 'nikhildfdfdfuzxsznikhilweszxnikhil'
Set @SubStr = 'nikhil'
Select (Len(@MainStr) - Len(REPLACE(@MainStr,@SubStr,'')))/Len(@SubStr)

0

SQL 2017 या उच्चतर में, आप इसका उपयोग कर सकते हैं:

declare @hits int = 0
set @hits = (select value from STRING_SPLIT('F609,4DFA,8499',','));
select count(@hits)

0

यह 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


0

SQL सर्वर 2017 के लिए

declare @hits int = 0;
set @hits = (select count(*) from (select value from STRING_SPLIT('F609,4DFA,8499',',')) a);
select @hits;

-1

आप मूल्यों को लाने के लिए निम्न संग्रहीत कार्यविधि का उपयोग कर सकते हैं।

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

इस संग्रहीत प्रक्रिया की पंक्ति 4 @c1उस उत्तर पर सेट होती है, जिसकी उसे आवश्यकता होती है। बाकी कोड क्या उपयोग है, इस पर विचार करते हुए कि इसे काम करने के लिए एक पूर्व मौजूदा तालिका की आवश्यकता है table1, जिसमें एक कठोर कोडित परिधि है, और दो महीने पहले से स्वीकृत उत्तर की तरह इनलाइन का उपयोग नहीं किया जा सकता है?
Nick.McD मत्स्यांगना

-1

बदलें / लेन परीक्षण प्यारा है, लेकिन शायद बहुत अक्षम (विशेष रूप से स्मृति के संदर्भ में)। लूप के साथ एक सरल कार्य काम करेगा।

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

प्रशंसनीय आकार की किसी भी तालिका के पार, एक प्रक्रियात्मक फ़ंक्शन का उपयोग करना कहीं अधिक
अक्षम्य

अच्छी बात। निर्मित लेन बहुत तेजी से कॉल कर रहे हैं तो एक प्रयोग परिभाषित समारोह?
डारेल ली

बड़े पैमाने पर रिकॉर्ड, हाँ। हालांकि कुछ होने के लिए आपको बड़े स्ट्रिंग्स के साथ बड़े रिकॉर्डसेट पर परीक्षण करना होगा। एसक्यूएल में कभी भी कुछ प्रक्रियात्मक न लिखें अगर आप इससे बच सकते हैं (यानी लूप्स)
Nick.McD मत्स्यांगना

-3

शायद आपको उस तरह से डेटा स्टोर नहीं करना चाहिए। एक क्षेत्र में कभी भी अल्पविराम सीमांकित सूची को संग्रहीत करना एक बुरा अभ्यास है। IT क्वेरी करने के लिए बहुत अक्षम है। यह संबंधित तालिका होनी चाहिए।


उस विचार के लिए +1। यह वह है जो मैं आमतौर पर तब शुरू करता हूं जब कोई व्यक्ति किसी क्षेत्र में अल्पविराम से अलग किए गए डेटा का उपयोग करता है।
गुफा

6
इस प्रश्न के उद्देश्य का एक हिस्सा मौजूदा डेटा को उस तरह से लेना और उसे अलग-अलग विभाजित करना था।
ओरियन एड्रियन

7
हम में से कुछ को विरासत डेटाबेस दिए गए हैं जहाँ यह किया गया था और हम इसके बारे में कुछ नहीं कर सकते।
eddieroger

@ मल्मोथ, निश्चित रूप से यह एक उत्तर है। आप समस्या को ठीक करते हैं लक्षण नहीं। समस्या डेटाबेस डिजाइन के साथ है।
एचएलजीईएम

1
@HLGEM प्रश्न हो सकता है एक समस्या को इंगित है, लेकिन यह अधिक सामान्य समझा जा सकता है। प्रश्न बहुत अच्छी तरह से सामान्यीकृत डेटाबेस के लिए पूरी तरह से वैध है।
Zeemee
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.