2011-02-10 22 views
1

私は処理しようとしているデータのフォーマットを制御できません。もちろん、データベース以外の次の問題に対処するためにスクリプト言語を使用することもできますが、私が扱うデータの量と手動の必要性を排除したいので避けたいと思いますステップ。列に埋め込まれたリストと範囲をどのように扱うことができますか?

要するに、私はリストの表を持っています。リストは、単一の3桁の文字列、複数の3桁の文字列、3桁の文字列の範囲などで構成されます。 012-018、または3桁の文字列の範囲と3桁の文字列の範囲。たとえば:

drop table list; 
drop table lists; 

create table lists (id varchar, vals varchar); 

insert into lists values('A', '001,003-005'); 
insert into lists values('B', '008-007'); 
insert into lists values('C', '010, 011, 012'); 
insert into lists values('D', '011-013, 016-018, 020'); 

私はを知って、を知っています。

私は、次の表にこれを有効にしたいと思います:

create table list (id varchar, val varchar); 
A 001 
A 003 
A 004 
A 005 
B 008 
B 007 
C 010 
C 011 
C 012 
D 011 
D 012 
D 013 
D 016 
D 017 
D 018 
D 020

は、SQLでこれを行う方法はありますか?

+0

どのRDBMSを使用していますか? –

+0

私はSASの 'PROC SQL'でこれを実際に実行しています。 –

+1

質問があれば、それは純粋なSQLで行うことができますか?いいえ、現実的ではありません。 SQLの達人がこれをcodegolfに変えて、それを行うための理解できないSQL文を書くことができますか?しかし、私はそれを維持したくありません。特定のバラエティがサポートしている手続き型言語を使用してデータベース側で行うことはできますか...絶対に。 –

答えて

3

特定のRDBMSで質問にタグを付けていないので、一般的に回答する必要があります。

SQL自体は、基本的に文字列の分割である、あなたが探している基本操作を提供していません。つまり、自分で書くか、の1つをオンラインで公開する必要があります。

あなたのデータには範囲がありますが、少し複雑です。 (代替的に、またはそれを行うには、カーソルを使用して)一時/メモリテーブルにデータを挿入して、手続き的にそれを反復

  1. の場合:これはあなたの手順では、このような何かを見に行くされていることを意味しますあなたのセットの各レコードは、正規化されていない文字列データを抽出し、','で分割します。
  2. 分割データ内の各要素については、'-'(これは範囲外要素の場合は1つの結果を返す)に分割する必要があります。
  3. 2番目の分割('-')の結果が1つの場合は、最終的な宛先に挿入できる単一のレコードです。それは二つの結果が得られた場合、それは範囲だとあなたは(要素1およびその分割の2を使用して)最初から最後まで反復してコメントした後、最終目的地

編集にレコードを挿入する必要があります

残念ながら、私はPROC SQLやSASに精通していませんので、具体的な解決策はありません。私はSQL Server T-SQLに以下のようなものを投稿することができます。

declare @results table (idx int identity(1, 1), id varchar(5), data varchar(max)) 
declare @elements table (idx int identity(1, 1), element varchar(25)) 
declare @range table (idx int identity(1, 1), element varchar(25)) 

insert into @results (id, data) 
select 
    your_id, 
    your_data 

from your_source 

declare @i int 
declare @cnt int 

declare @j int 
declare @cnt2 int 

declare @element varchar(25) 

declare @first int 
declare @second int 

declare @start int 
declare @end int 

declare @id varchar(5) 
declare @data varchar(max) 

select @i = min(idx) - 1, @cnt = max(idx) from @results 

while @i < @cnt 
begin 
    select @i = @i + 1 

    select @id = id, @data = data from @results where idx = @i 

    delete @elements 

    insert into @elements (element) 
    select 
     element 

    from split(@data, ',') 

    select @j = min(idx) - 1, @cnt2 = max(idx) from @elements 

    while @j < @cnt2 
    begin 
     select @j = @j + 1 

     select @element = element from @elements where idx = @j 

     delete @range 

     insert into @range (element) 
     select 
      element 

     from split(@element, '-') 

     select @first = min(idx), @second = max(idx) from @range 

     if @first = @second --single element 
      insert into final_destination (id, value) 
      select 
       @id, 
       element 

      from @range 
     else if @second - @first = 1 -- two elements, as desired 
     begin 
      select @start = convert(int, element) - 1 from @range where idx = @first 
      select @end = convert(int, element) from @range where idx = @second 

      while @start < @end 
      begin 
       select @start = @start + 1 

       insert into final_destination (id, value) 
       values (@id, @start) 
      end 
     end 
     else -- error condition, bad input 
    end 
end 
+0

これは私が自分自身を思い付くことができるものより優れています。私はあきらめる前にこの論理に従って何かを実装できるかどうかを見極めるつもりです。 ;-) –

関連する問題