2017-12-06 12 views
2

私は、テーブルに次の二つの文字列があります。私は、これら2つから以下の情報を抽出したいSQL分割文字列

CN=ABCDEFG,OU=7SOE,OU=TEMP,OU=Sydney,OU=Australia,DC=LDAP,DC=COM 
CN=ABCDEFGHIJ,OU=7SOEFHU,OU=TEST,OU=TEMP,OU=London,OU=Europe,DC=LDAP,DC=COM 

を:

Sydney 
London 

私はRIGHT、SUBSTRINGとCHARINDEXを使用し始めたが、基本的に右から 'OU ='を使ってパターンを右から分割することができませんでした。見た目が乱雑で、C#でできるように、文字列を分割するエレガントな方法はありません。 - SQL 2014.

答えて

1

SQLで分割文字列関数を使用して、文字列を配列に分割し、 'OU ='部分文字列で行にアクセスすることができます。

SELECT value FROM STRING_SPLIT('Lorem,ipsum,dolor,sit,amet.', ','); 

またはあなたがOU=の最後のインスタンスの隣をしたいのように、ここで

Split data in sql with multiple delimiters (, and -) with owns rule

https://raresql.com/2013/01/10/sql-server-split-string-into-rows-based-on-multiple-delimiters/

+0

どのようにOU =彼はそれを分割しましたか? –

+0

humm !!!サブストリングはここで動作するか、再度stringsplitを使用して2番目の行を取得することができます – BlindSniper

+0

おそらく私は2014年のSQLを持っていないでしょう、それは2012年でなければなりません、悲しいことにSTRING_SPLIT機能はありません – user512628

0

を説明する方法は、ルックス使用できる以下のようにそのための構文は次のとおりです。これを行う方法は次のとおりです。

declare @table table (c1 varchar(256)) 
insert into @table 
values 
('CN=ABCDEFG,OU=7SOE,OU=TEMP,OU=Sydney,OU=Australia,DC=LDAP,DC=COM'), 
('CN=ABCDEFGHIJ,OU=7SOEFHU,OU=TEST,OU=TEMP,OU=London,OU=Europe,DC=LDAP,DC=COM') 


select 
    right(left(c1, len(c1) - charindex('UO',reverse(c1)) - 2),charindex('UO',reverse(left(c1, len(c1) - charindex('UO',reverse(c1)) - 2))) - 2) 
from @table 

ただ、それぞれ、自分の列名とテーブル名でc1@tableを交換してください。

素早く分割するには、Jeff Modenのおかげで非常に高速な処理ができる関数があります。ここで

CREATE FUNCTION [dbo].[DelimitedSplit8K] (@pString VARCHAR(8000), @pDelimiter CHAR(1)) 
--WARNING!!! DO NOT USE MAX DATA-TYPES HERE! IT WILL KILL PERFORMANCE! 

RETURNS TABLE WITH SCHEMABINDING AS 
RETURN 

/* "Inline" CTE Driven "Tally Table" produces values from 1 up to 10,000... 
enough to cover VARCHAR(8000)*/ 

    WITH E1(N) AS (
       SELECT 1 UNION ALL SELECT 1 UNION ALL SELECT 1 UNION ALL 
       SELECT 1 UNION ALL SELECT 1 UNION ALL SELECT 1 UNION ALL 
       SELECT 1 UNION ALL SELECT 1 UNION ALL SELECT 1 UNION ALL SELECT 1 
       ),       --10E+1 or 10 rows 
     E2(N) AS (SELECT 1 FROM E1 a, E1 b), --10E+2 or 100 rows 
     E4(N) AS (SELECT 1 FROM E2 a, E2 b), --10E+4 or 10,000 rows max 
cteTally(N) AS (--==== This provides the "base" CTE and limits the number of rows right up front 
        -- for both a performance gain and prevention of accidental "overruns" 
       SELECT TOP (ISNULL(DATALENGTH(@pString),0)) ROW_NUMBER() OVER (ORDER BY (SELECT NULL)) FROM E4 
       ), 
cteStart(N1) AS (--==== This returns N+1 (starting position of each "element" just once for each delimiter) 
       SELECT 1 UNION ALL 
       SELECT t.N+1 FROM cteTally t WHERE SUBSTRING(@pString,t.N,1) = @pDelimiter 
       ), 
cteLen(N1,L1) AS(--==== Return start and length (for use in substring) 
       SELECT s.N1, 
         ISNULL(NULLIF(CHARINDEX(@pDelimiter,@pString,s.N1),0)-s.N1,8000) 
        FROM cteStart s 
       ) 
--===== Do the actual split. The ISNULL/NULLIF combo handles the length for the final element when no delimiter is found. 
SELECT ItemNumber = ROW_NUMBER() OVER(ORDER BY l.N1), 
     Item  = SUBSTRING(@pString, l.N1, l.L1) 
    FROM cteLen l 
; 

GO 

は、あなたの状況でそれを使用することができる方法である:

select 
    t.c1 
    ,x.ItemNumber     --this represents the item number in the string. 
    ,x.Item       --this is the value of that item 
    ,RN = row_number() over (partition by c1 order by x.ItemNumber desc) 
from 
    @table t 
    cross apply 
    dbo.DelimitedSplit8K(c1,',') x 
--where 
-- left(x.Item,2) = 'OU'   --uncomment this out to see how the RN will be used in the CTE below 
order by 
    t.c1, 
    x.ItemNumber 

だから、唯一のあなたが望む結果を得るために、我々は唯一のOUと順序で始まる項目にrow_number()を適用しますそれらは衰退している。したがって、row_number()= 2(最後から2番目)は、必要な値になります。

;with cte as(
select 
    * 
    ,RN = row_number() over (partition by c1 order by x.ItemNumber desc) 
from 
    @table 
    cross apply 
    dbo.DelimitedSplit8K(c1,',') x 
where 
    left(x.Item,2) = 'OU') 

select 
    c1, 
    YourExtract = right(Item,len(Item) - 3) 
from 
    cte 
where 
    RN = 2