2012-01-04 14 views
21

में वें घटना को खोजने मैं एक तालिका स्तंभ है कि मूल्यों में इस तरह के abc_1_2_3_4.gif या zzz_12_3_3_45.gif आदिएसक्यूएल सर्वर - एक स्ट्रिंग

के रूप में मैं के प्रत्येक _ अंडरस्कोर ऊपर मूल्यों में सूचकांक को खोजने के लिए चाहते हैं की है। वहां केवल चार अंडरस्कोर होंगे लेकिन यह देखते हुए कि वे स्ट्रिंग में किसी भी स्थिति में हो सकते हैं, मैं इसे कैसे प्राप्त कर सकता हूं?

मैं substring और charindex समारोह की कोशिश की है, लेकिन मैं केवल मज़बूती से पहले एक को पकड़ कर सकते हैं। कोई विचार?

+0

एक कर्सर आपके लिए एक समाधान है? – danihp

+0

@adrianos - आप कितने डेटा सेट की अपेक्षा कर रहे हैं? एसक्यूएल सर्वर का संस्करण क्या है? – EBarr

उत्तर

31

एक ही रास्ता (2k8) है;

select 'abc_1_2_3_4.gif  ' as img into #T 
insert #T values ('zzz_12_3_3_45.gif') 

;with T as (
    select 0 as row, charindex('_', img) pos, img from #T 
    union all 
    select pos + 1, charindex('_', img, pos + 1), img 
    from T 
    where pos > 0 
) 
select 
    img, pos 
from T 
where pos > 0 
order by img, pos 

>>>> 

img     pos 
abc_1_2_3_4.gif  4 
abc_1_2_3_4.gif  6 
abc_1_2_3_4.gif  8 
abc_1_2_3_4.gif  10 
zzz_12_3_3_45.gif 4 
zzz_12_3_3_45.gif 7 
zzz_12_3_3_45.gif 9 
zzz_12_3_3_45.gif 11 

अद्यतन

;with T(img, starts, pos) as (
    select img, 1, charindex('_', img) from #t 
    union all 
    select img, pos + 1, charindex('_', img, pos + 1) 
    from t 
    where pos > 0 
) 
select 
    *, substring(img, starts, case when pos > 0 then pos - starts else len(img) end) token 
from T 
order by img, starts 

>>> 

img     starts pos  token 
abc_1_2_3_4.gif   1  4  abc 
abc_1_2_3_4.gif   5  6  1 
abc_1_2_3_4.gif   7  8  2 
abc_1_2_3_4.gif   9  10  3 
abc_1_2_3_4.gif   11  0  4.gif   
zzz_12_3_3_45.gif 1  4  zzz 
zzz_12_3_3_45.gif 5  7  12 
zzz_12_3_3_45.gif 8  9  3 
zzz_12_3_3_45.gif 10  11  3 
zzz_12_3_3_45.gif 12  0  45.gif 
+0

हम्म, अवैध ऑब्जेक्ट नाम '#t'। – adrianos

+1

यह मेरे टेस्ट डेटा से @ शीर्ष '... # टी' में सही ऑब्जेक्ट नाम –

+0

वास्तव में खेद है, इसे इस तरह से काम नहीं कर सका - sqlserver मेरा मजबूत सूट नहीं है! हालांकि धन्यवाद में +1। – adrianos

7

आप function से split the values पर delimiter का उपयोग कर सकते हैं। यह return a table होगा और nth घटना को खोजने के लिए बस select बनाएं! या इसे return पर table के बजाय इसकी आवश्यकता के लिए थोड़ा सा बदलें।

CREATE FUNCTION dbo.Split 
(
    @RowData nvarchar(2000), 
    @SplitOn nvarchar(5) 
) 
RETURNS @RtnValue table 
(
    Id int identity(1,1), 
    Data nvarchar(100) 
) 
AS 
BEGIN 
    Declare @Cnt int 
    Set @Cnt = 1 

    While (Charindex(@SplitOn,@RowData)>0) 
    Begin 
     Insert Into @RtnValue (data) 
     Select 
      Data = ltrim(rtrim(Substring(@RowData,1,Charindex(@SplitOn,@RowData)-1))) 

     Set @RowData = Substring(@RowData,Charindex(@SplitOn,@RowData)+1,len(@RowData)) 
     Set @Cnt = @Cnt + 1 
    End 

    Insert Into @RtnValue (data) 
    Select Data = ltrim(rtrim(@RowData)) 

    Return 
END 
+0

एक गति राक्षस समारोह नहीं है, लेकिन इन प्रश्नों के लिए बहुत उपयोगी है मुझे लगता है कि मुझे लगातार लिखना पड़ता है! बहुत अच्छा काम करता है! – Limey

+0

@ लाइमी अगर ऐसा होता है तो कई बार एक और समाधान का उपयोग करने का प्रयास करें। कर्सर एसक्यूएल सर्वर में जाने का तरीका नहीं है;) –

2

आप look for the four underscore in this way कर सकते हैं:

create table #test 
(t varchar(50)); 

insert into #test values 
('abc_1_2_3_4.gif'), 
('zzz_12_3_3_45.gif'); 

declare @t varchar(50); 
declare @t_aux varchar(50); 
declare @t1 int; 
declare @t2 int; 
declare @t3 int; 
declare @t4 int; 

DECLARE t_cursor CURSOR 
    FOR SELECT t FROM #test 
OPEN t_cursor 
FETCH NEXT FROM t_cursor into @t;​ 
set @t1 = charindex('_', @t) 
set @t2 = charindex('_', @t , @t1+1) 
set @t3 = charindex('_', @t , @t2+1) 
set @t4 = charindex('_', @t , @t3+1) 

select @t1, @t2, t3, t4 

--do a loop to iterate over all table 

आप इसे यहां से परीक्षण कर सकते हैं।

या इस सरल तरीके से:

select 
    charindex('_', t) as first, 
    charindex('_', t, charindex('_', t) + 1) as second, 
    ... 
from 
    #test 
1

मेरे एसक्यूएल एक substring_Index जहां यह n घटना के लिए एक स्ट्रिंग में एक मूल्य की स्थिति वापस आ जाएगी के समारोह का समर्थन करता है। इसे प्राप्त करने के लिए एक समान उपयोगकर्ता परिभाषित फ़ंक्शन लिखा जा सकता है। उदाहरण link

वैकल्पिक रूप से आप पहले से मिले उदाहरण के प्रारंभिक पोस्ट +1 के बाद प्रत्येक _ के स्थान की रिपोर्ट करने के लिए charindex फ़ंक्शन कॉल का उपयोग कर सकते हैं। जब तक एक 0

पाया जाता है

संपादित करें: समुद्री मील दूर CHARINDEX सही समारोह

+0

मुझे MySQL में substring_index पसंद है जो यह एक क्वेरी के साथ करता है। निश्चित नहीं है कि एमएस क्यों सोचता है कि इसे SQL सर्वर में लागू नहीं किया जा सकता है मेरे बाहर है। ऐसा कुछ लागू करने के लिए रॉकेट वैज्ञानिक नहीं लेता है! – ThinkCode

0

मैं एक समारोह का उपयोग किया है बड़ी सफलता के साथ तत्व "वें" एक सीमांकित स्ट्रिंग क्षेत्र से हड़पने के लिए। उपरोक्त वर्णित की तरह, यह चीजों से निपटने का एक "तेज़" तरीका नहीं है, लेकिन यह सुनिश्चित है कि बिल्ली सुविधाजनक है।

create function GetArrayIndex(@delimited nvarchar(max), @index int, @delimiter nvarchar(100) = ',') returns nvarchar(max) 
as  
begin  
declare @xml xml, @result nvarchar(max) 
set @xml = N'<root><r>' + replace(@delimited, @delimiter,'</r><r>') + '</r></root>' 
select @result = r.value('.','varchar(max)') 
from @xml.nodes('//root/r[sql:variable("@index")]') as records(r) 

return @result 
end  
6

आप CHARINDEX का उपयोग करें और प्रारंभिक स्थान निर्दिष्ट कर सकते हैं:

DECLARE @x VARCHAR(32) = 'MS-SQL-Server'; 

SELECT 
    STUFF(STUFF(@x,3 , 0, '/'), 8, 0, '/') InsertString 
    ,CHARINDEX('-',LTRIM(RTRIM(@x))) FirstIndexOf 
    ,CHARINDEX('-',LTRIM(RTRIM(@x)), (CHARINDEX('-', LTRIM(RTRIM(@x)))+1)) SecondIndexOf 
    ,CHARINDEX('-',@x,CHARINDEX('-',@x, (CHARINDEX('-',@x)+1))+1) ThirdIndexOf 
    ,CHARINDEX('-',REVERSE(LTRIM(RTRIM(@x)))) LastIndexOf; 
GO 
2

आप चर/सरणी छीलने की कोशिश कर सकते हैं, अपनी सूची में स्पष्टता संभालने

declare @array table ----table of values 
(
    id int identity(1,1) 
    ,value nvarchar(max) 
) 
DECLARE @VALUE NVARCHAR(MAX)='val1_val2_val3_val4_val5_val6_val7'----string array 
DECLARE @CURVAL NVARCHAR(MAX)  ---current value 
DECLARE @DELIM NVARCHAR(1)='_' ---delimiter 
DECLARE @BREAKPT INT    ---current index of the delimiter 

WHILE EXISTS (SELECT @VALUE) 
    BEGIN 
     SET @BREAKPT=CHARINDEX(@DELIM,@VALUE) ---set the current index 
     --- 
     If @BREAKPT<> 0       ---index at 0 breaks the loop 
      begin 
       SET @CURVAL=SUBSTRING(@VALUE,1,@BREAKPT-1)     ---current value 
       set @VALUE=REPLACE(@VALUE,SUBSTRING(@VALUE,1,@BREAKPT),'') ---current value and delimiter, replace 
       insert into @array(value)         ---insert data 
       select @CURVAL 
      end 
     else 
      begin 
       SET @[email protected]           ---current value now last value 
       insert into @array(value)         ---insert data 
       select @CURVAL 
       break              ---break loop 
      end 
    end 

select * from @array ---find nth occurance given the id 
0

के लिए एक साधारण नमूना xml रूपांतरण के साथ ऐसा करें:

SELECT 'A|B|C' 
    , concat('<x>', REPLACE('A|B|C', '|', '</x><x>'), '</x>') 
    , cast(concat('<x>', REPLACE('A|B|C', '|', '</x><x>'), '</x>') as xml).query('/x[2]') 
    , cast(concat('<x>', REPLACE('A|B|C', '|', '</x><x>'), '</x>') as xml).value('/x[2]',  
     'varchar'); 

और यहाँ अपने नमूना के लिए एक अनुवाद:

SELECT gifname 
     ,cast(concat('<x>', REPLACE(gifname, '_', '</x><x>'), '</x>') as xml).query('/x[2]') as xmlelement 
    , cast(concat('<x>', REPLACE(gifname, '_', '</x><x>'), '</x>') as xml).value('/x[2]', 'varchar(10)') as result 
    FROM (
     SELECT 'abc_1_2_3_4.gif' as gifname 
     UNION ALL 
     SELECT 'zzz_12_3_3_45.gif' 
    ) tmp 
1

मैं इस बनाने के लिए कई अलग कस्टम काम करता है, की खोज चरित्र यानी 2 की प्रत्येक स्थिति के लिए एक, 3 की थी:।

बनाएं फंक्शन [dbo] [ fnCHARPOS2] (@SEARCHCHAR VARCHAR (255), @SEARCHSTRING VARCHAR (255)) रिटर्न INT के रूप में शुरू रिटर्न CHARINDEX (@ SEARCHCHAR, @ SEARCHSTRING (CHARINDEX (@ SEARCHCHAR, @ SEARCHSTRING, 0) +1)) ;

CREATE FUNCTION [dbo].[fnCHARPOS3] 
(@SEARCHCHAR VARCHAR(255), 
@SEARCHSTRING VARCHAR(255)) 
RETURNS INT 
AS 
BEGIN 
RETURN CHARINDEX(@SEARCHCHAR,@SEARCHSTRING, (CHARINDEX(@SEARCHCHAR,@SEARCHSTRING, (CHARINDEX(@SEARCHCHAR,@SEARCHSTRING,0)+1)))+1); 

फिर आप चरित्र आप खोज रहे हैं और स्ट्रिंग आप में खोज कर रहे हैं एक पैरामीटर के रूप में पारित कर सकते हैं:

तो अगर आप 'एफ' के लिए खोज कर रहे थे और 1 3 की स्थिति जानना चाहता था अवसर:

select 
database.dbo.fnCHARPOS2('f',tablename.columnname), 
database.dbo.fnCHARPOS3('f',tablename.columnname) 
from tablename 

यह मेरे लिए काम करता है!

1

मैंने एक रिकर्सिव फ़ंक्शन का उपयोग करने का निर्णय लिया क्योंकि मेरे लिए तर्क का पालन करना आसान था। ध्यान दें कि SQL सर्वर में 32 की डिफ़ॉल्ट फ़ंक्शन रिकर्सन सीमा है, इसलिए यह छोटे वर्कलोड के लिए केवल अच्छा है।

create function dbo._charindex_nth (
    @FindThis varchar(8000), 
    @InThis varchar(max), 
    @StartFrom int, 
    @NthOccurence tinyint 
) 
returns bigint 
as 
begin 
    /* 
    Recursive helper used by dbo.charindex_nth to return the position of the nth occurance of @FindThis in @InThis 

    Who When What 
    PJR 160421 Initial 
    */ 

    declare @Pos bigint 

    if isnull(@NthOccurence, 0) <= 0 or isnull(@StartFrom, 0) <= 0 
    begin 
    select @Pos = 0 
    end else begin 
    if @NthOccurence = 1 
    begin 
     select @Pos = charindex(@FindThis, @InThis, @StartFrom) 
    end else begin 
     select @Pos = dbo._charindex_nth(@FindThis, @InThis, nullif(charindex(@FindThis, @InThis, @StartFrom), 0) + 1, @NthOccurence - 1) 
    end 
    end 

    return @Pos 
end 

create function dbo.charindex_nth (
    @FindThis varchar(8000), 
    @InThis varchar(max), 
    @NthOccurence tinyint 
) 
returns bigint 
as 
begin 
    /* 
    Returns the position of the nth occurance of @FindThis in @InThis 

    Who When What 
    PJR 160421 Initial 
    */ 

    return dbo._charindex_nth(@FindThis, @InThis, 1, @NthOccurence) 
end 

declare @val varchar(max) = 'zzz_12_3_3_45.gif' 

select dbo.charindex_nth('_', @val, 1) Underscore1 
    , dbo.charindex_nth('_', @val, 2) Underscore2 
    , dbo.charindex_nth('_', @val, 3) Underscore3 
    , dbo.charindex_nth('_', @val, 4) Underscore4 
0

मैंने पैटिंडेक्स और एक रेगेक्स सीएलआर असेंबली का उपयोग कर SQL सर्वर में कुछ ऐसा किया है जो मानों की एक सरणी देता है। यदि आप इसे आज़माएं, तो मैं काम पर आने पर नमूना अपलोड कर सकता हूं।

0

मैं स्ट्रिंग के माध्यम से बस इसे करने के बजाय ऐसा करने के लिए एक तेज़ तरीका से टकरा रहा था।

CREATE FUNCTION [ssf_GetNthSeparatorPosition] (@TargetString VARCHAR(MAX) 
               , @Sep VARCHAR(25) 
               , @n INTEGER) 
RETURNS INTEGER 
/**************************************************************************************** 
--############################################################################# 
-- Returns the position of the Nth Charactor sequence 
--          123456789
-- Declare @thatString varchar(max) = 'hi,there,jay,yo' 
    Select dbo.ssf_GetNthSeparatorPosition(@thatString, ',', 3) --would return 13 
--############################################################################ 


****************************************************************************************/ 
AS 
    BEGIN 
     DECLARE @Retval INTEGER = 0 
     DECLARE @CurPos INTEGER = 0 
     DECLARE @LenSep INTEGER = LEN(@Sep) 

     SELECT @CurPos = CHARINDEX(@Sep, @TargetString) 

     IF ISNULL(@LenSep, 0) > 0 
      AND @CurPos > 0 
      BEGIN 

       SELECT @CurPos = 0 
       ;with lv0 AS (SELECT 0 g UNION ALL SELECT 0) 
          ,lv1 AS (SELECT 0 g FROM lv0 a CROSS JOIN lv0 b) -- 4 
          ,lv2 AS (SELECT 0 g FROM lv1 a CROSS JOIN lv1 b) -- 16 
          ,lv3 AS (SELECT 0 g FROM lv2 a CROSS JOIN lv2 b) -- 256 
          ,lv4 AS (SELECT 0 g FROM lv3 a CROSS JOIN lv3 b) -- 65,536 
          ,lv5 AS (SELECT 0 g FROM lv4 a CROSS JOIN lv4 b) -- 4,294,967,296 
          ,Tally (n) AS (SELECT ROW_NUMBER() OVER (ORDER BY (SELECT NULL)) FROM lv5), 
         results 
          AS (SELECT n - LEN(@Sep) AS Nth 
           , row_number() OVER (ORDER BY n) - 1 AS Position 
           FROM Tally t 
           WHERE n BETWEEN 1 
             AND  DATALENGTH(@TargetString) + DATALENGTH(@Sep) 
            AND SUBSTRING(@Sep + @TargetString, n, LEN(@Sep)) = @Sep) 
        SELECT @CurPos = Nth 
         FROM results 
         WHERE results.Position = @n 


      END 
     RETURN @CurPos 

    END 

GO 
3
DECLARE @str AS VARCHAR(100) 
SET @str='1,2 , 3, 4, 5,6' 
SELECT COALESCE(LTRIM(CAST(('<X>'+REPLACE(@str,',' ,'</X><X>')+'</X>') AS XML).value('(/X)[1]', 'varchar(128)')), ''), 
     COALESCE(LTRIM(CAST(('<X>'+REPLACE(@str,',' ,'</X><X>')+'</X>') AS XML).value('(/X)[2]', 'varchar(128)')), ''), 
     COALESCE(LTRIM(CAST(('<X>'+REPLACE(@str,',' ,'</X><X>')+'</X>') AS XML).value('(/X)[3]', 'varchar(128)')), ''), 
     COALESCE(LTRIM(CAST(('<X>'+REPLACE(@str,',' ,'</X><X>')+'</X>') AS XML).value('(/X)[4]', 'varchar(128)')), ''), 
     COALESCE(LTRIM(CAST(('<X>'+REPLACE(@str,',' ,'</X><X>')+'</X>') AS XML).value('(/X)[5]', 'varchar(128)')), ''), 
     COALESCE(LTRIM(CAST(('<X>'+REPLACE(@str,',' ,'</X><X>')+'</X>') AS XML).value('(/X)[6]', 'varchar(128)')), ''), 
     COALESCE(LTRIM(CAST(('<X>'+REPLACE(@str,',' ,'</X><X>')+'</X>') AS XML).value('(/X)[7]', 'varchar(128)')), ''), 
     COALESCE(LTRIM(CAST(('<X>'+REPLACE(@str,',' ,'</X><X>')+'</X>') AS XML).value('(/X)[8]', 'varchar(128)')), ''), 
     COALESCE(LTRIM(CAST(('<X>'+REPLACE(@str,',' ,'</X><X>')+'</X>') AS XML).value('(/X)[9]', 'varchar(128)')), '') 
+0

से धन्यवाद। किसी तालिका में अलग होने के लिए सूची में केवल 3 आइटमों की आवश्यकता होती है और अन्य सभी समाधान भी looooooooooong हैं :) – user2065377

2

आप एक ही समारोह के अंदर की स्थिति के लिए +1 CHARINDEX ('', [TEXT], (CHARINDEX ('', [TEXT], 1)) + 1) में उपयोग कर सकते हैं जहां +1 वह समय है जिसे आप ढूंढना चाहते हैं।

2
DECLARE @LEN INT 
DECLARE @VAR VARCHAR(20) 
SET @VAR = 'HELLO WORLD' 
SET @LEN = LEN(@VAR) 
--SELECT @LEN 
SELECT PATINDEX('%O%',SUBSTRING(@VAR,PATINDEX('%O%' ,@VAR) + 1 ,PATINDEX('%O%',@VAR) + 1)) + PATINDEX('%O%',@VAR) 
+1

यह आपके कोड के साथ स्पष्टीकरण जोड़ने योग्य होगा। कोड डंप अक्सर डाउनवॉटेड होते हैं और हटा दिए जा सकते हैं। उत्तर देखो]। – Bugs

+0

ठीक है मैं – Mayur

+0

का पालन करूंगा यह स्ट्रिंग – Mayur

0
declare @a nvarchar(50)='Enter Your string ' 
declare @character char='e' 
declare @nthoccurence int = 2 
declare @i int = 1 
declare @j int =0 
declare @count int = len(@a)-len(replace(@a,@character,'')) 

if(@count >= @nthoccurence) 
begin 
     while (@I <= @nthoccurence) 
     begin 
      set @j= CHARINDEX(@character,@a,@j+1) 
      set @i= @i+1 
     end 
     print @j 
end 
else 
    Print 'you have only '+convert(nvarchar ,@count)+' occurrences of '[email protected] 
end 
+0

कृपया अपना कोड समझाएं और इसे अन्य उत्तर दिए गए समाधानों से अलग कैसे बनाता है। – Markus

0
DECLARE @x VARCHAR(32) = 'MS-SQL-Server'; 

SELECT 
SUBSTRING(@x,0,CHARINDEX('-',LTRIM(RTRIM(@x)))) A, 
SUBSTRING(@x,CHARINDEX('-',LTRIM(RTRIM(@x)))+1,CHARINDEX('-' 
,LTRIM(RTRIM(@x)))) B, 
SUBSTRING(@x,CHARINDEX('-',REVERSE(LTRIM(RTRIM(@x))))+1,LEN(@x)-1) C 


A B C 
MS SQL Server 
संबंधित मुद्दे