2017-12-25 21 views
3

これは私の質問hereのフォローアップです:uziによって提供された素晴らしい質問があります。私はしかし、新しい会社、Company3も、単一のデータポイントを使用していることに気付きました。アカ​​ウント6000は、以前の会社の方法に従わず、uziの再帰的なcteを適用できませんでした。連結された値の単一の文字列から行に分割された最低値と最高値を見つける

このように私は質問を変更する必要があるように感じますが、この複雑な問題は解決策に大きな影響を与えるため、私の前の編集ではなく新しい質問を発行すると考えています。

私は、データがこのように格納されたExcelワークブックからデータを読み取る必要が

Company  Accounts 
Company1  (#3000...#3999) 
Company2  (#4000..#4019)+(#4021..#4024) 
Company3  (#5000..#5001)+#6000+(#6005..#6010) 

私はこのようなCompany3などいくつかの企業になるようにI #6000としてアカウントの単一の値を持つと信じています私はそのような一つとして、ファイナルテーブルの外観を取得するには、整数のみのテーブルで、このテーブルを使用し、それに参加する

Company  FirstAcc LastAcc 
Company1  3000  3999 
Company2  4000  4019 
Company2  4021  4024 
Company3  5000  5001 
Company3  6000  NULL 
Company3  6005  6010 

:このステップでは、以下のappearenceの結果セットを作成する必要があります私のリンクされたq憂鬱。

誰にもアイデアはありますか?

+0

問題が解決しましたか? – Hadi

答えて

1

良いT-SQLスプリッタ機能は、これは非常に簡単になります。私はdelimitedSplit8kを提案する。これは、再帰CTEよりも大幅に優れたパフォーマンスを発揮します。まず、サンプルデータ:

-- your sample data 
if object_id('tempdb..#yourtable') is not null drop table #yourtable; 
create table #yourtable (company varchar(100), accounts varchar(8000)); 
insert #yourtable values ('Company1','(#3000...#3999)'), 
('Company2','(#4000..#4019)+(#4021..#4024)'),('Company3','(#5000..#5001)+#6000+(#6005..#6010)'); 

とソリューション:

select 
    company, 
    firstAcc = max(case when split2.item not like '%)' then clean.Item end), 
    lastAcc = max(case when split2.item  like '%)' then clean.Item end) 
from #yourtable t 
cross apply dbo.delimitedSplit8K(accounts, '+') split1 
cross apply dbo.delimitedSplit8K(split1.Item, '.') split2 
cross apply (values (replace(replace(split2.Item,')',''),'(',''))) clean(item) 
where split2.item > '' 
group by split1.Item, company; 

結果:私はそのリストを信じる

company firstAcc lastAcc 
--------- ---------- -------------- 
Company1 #3000  #3999 
Company2 #4000  #4019 
Company2 #4021  #4024 
Company3 #6000  NULL 
Company3 #5000  #5001 
Company3 #6005  #6010 
1

他の質問から@uzi解決策を少し編集しました。問題を解決するために、他の3つのCTEを追加し、窓機能をLEAD()ROW_NUMBER()のように使用しました。私は単純な解決策があるかどうかわかりませんが、これはうまくいくと思います。

with cte as (
select 
    company, replace(replace(replace(accounts,'(',''),')',''),'+','')+'#' accounts 
from 
    (values ('company 1','#3000..#3999'),('company 2','(#4000..#4019)+(#4021..#4024)'),('company 3','(#5000..#5001)+#6000+(#6005..#6010)')) data(company, accounts) 
) 
, rcte as (
    select 
     company, stuff(accounts, ind1, ind2 - ind1, '') acc, substring(accounts, ind1 + 1, ind2 - ind1 - 1) accounts 
    from 
     cte 
     cross apply (select charindex('#', accounts) ind1) ca 
     cross apply (select charindex('#', accounts, ind1 + 1) ind2) cb 
    union all 
    select 
     company, stuff(acc, ind1, ind2 - ind1, ''), substring(acc, ind1 + 1, ind2 - ind1 - 1) 
    from 
     rcte 
     cross apply (select charindex('#', acc) ind1) ca 
     cross apply (select charindex('#', acc, ind1 + 1) ind2) cb 
    where 
     len(acc)>1 
) ,cte2 as (

    select company, accounts as accounts_raw, Replace(accounts,'..','') as accounts, 
     LEAD(accounts) OVER(Partition by company ORDER BY accounts) ld, 
     ROW_NUMBER() OVER(ORDER BY accounts) rn 
    from rcte 
) , cte3 as (

    Select company,accounts,ld ,rn 
    from cte2 
    WHERE ld not like '%..' 
) , cte4 as (
    select * from cte3 where accounts not in (select ld from cte3 t1 where t1.rn < cte3.rn) 
) 

SELECT company,accounts,ld from cte4 
UNION 
SELECT DISTINCT company,ld,NULL from cte3 where accounts not in (select accounts from cte4 t1) 

option (maxrecursion 0) 

結果:

enter image description here

1

(#6005 ..#6010)は、#6005#のように表されます6006#6007#6008#6009#6010をExcelファイルに保存します。それが真実であるとはギャップ

with cte as (
select 
    company, replace(replace(replace(accounts,'(',''),')',''),'+','')+'#' accounts 
from 
    (values ('company 1','#3000#3001#3002#3003'),('company 2','(#4000#4001)+(#4021#4022)'),('company 3','(#5000#5001)+#6000+(#6005#6006)')) data(company, accounts) 
) 

, rcte as (
    select 
     company, stuff(accounts, ind1, ind2 - ind1, '') acc, substring(accounts, ind1 + 1, ind2 - ind1 - 1) accounts 
    from 
     cte 
     cross apply (select charindex('#', accounts) ind1) ca 
     cross apply (select charindex('#', accounts, ind1 + 1) ind2) cb 
    union all 
    select 
     company, stuff(acc, ind1, ind2 - ind1, ''), substring(acc, ind1 + 1, ind2 - ind1 - 1) 
    from 
     rcte 
     cross apply (select charindex('#', acc) ind1) ca 
     cross apply (select charindex('#', acc, ind1 + 1) ind2) cb 
    where 
     len(acc)>1 
) 

select 
    company, min(accounts) FirstAcc, case when max(accounts) =min(accounts) then null else max(accounts) end LastAcc 
from (
    select 
     company, accounts, accounts - row_number() over (partition by company order by accounts) group_ 
    from 
     rcte 
    ) t 
group by company, group_ 

option (maxrecursion 0) 
1

がないそれはあなたがSSISをタグ付けされたようなので、私は、スクリプトタスクを使用して、そのためのソリューションを提供します見える場合、この文字列で検索してください。他のすべての例では、ステージング表へのロードが必要です。

  1. 編集コンポーネント
  2. 入力列スクリプト変換コンポーネントの追加通常の読者(おそらくエクセル)と負荷
  3. を使用してください - 両方の会社をチェックして、
  4. 入力と出力のアカウントが - 新しいを追加します出力し、それをCompFirstLastと呼びます。
  5. 3つの列を追加します - Company string、First int、Last int
  6. Open Sc次のコードを貼り付けて貼り付けてください。

    public override void Input0_ProcessInputRow(Input0Buffer Row) 
    { 
    
    //Create an array for each group to create rows out of by splitting on '+' 
    
    string[] SplitForRows = Row.Accounts.Split('+'); //Note single quotes denoting char 
    
    //Deal with each group and create the new Output 
    for (int i = 0; i < SplitForRows.Length; i++) //Loop each split column 
        { 
         CompFirstLastBuffer.AddRow(); 
         CompFirstLastBuffer.Company = Row.Company; //This is static for each incoming row 
    
         //Clean up the string getting rid of(). and leaving a delimited list of # 
         string accts = SplitForRows[i].Replace("(", String.Empty).Replace(")", String.Empty).Replace(".", String.Empty).Substring(1); 
    
         //Split into Array 
         string[] accounts = accts.Split('#'); 
    
         // Write out first and last and handle null 
         CompFirstLastBuffer.First = int.Parse(accounts[0]); 
    
         if (accounts.Length == 1) 
          CompFirstLastBuffer.Last_IsNull = true; 
         else 
          CompFirstLastBuffer.Last = int.Parse(accounts[1]); 
    
        } 
    } 
    
  7. 正しい出力を使用してください。

+0

あなたのリストがuziのようなものなら(#3001#3002#3003)、最後の行を変更してください。CompFirstLastBuffer.Last = int.Parse(accounts [1]); 〜CompFirstLastBuffer.Last = int.Parse(accounts [accounts.length-1]); – KeithL

+0

また、1つの値に対してのみNULLを返す代わりに、両方を同じ値の開始と終了を与えるaccounts [0]に設定することもできます。私はあなたが将来論理の間でいくつかやっていると仮定しています。 – KeithL

+1

@ハディ...それを掃除していただきありがとうございます。私はコードのように見えるようにする方法を見つけることができませんでした – KeithL

関連する問題