2

処理しようとしているデータの形式を制御できません。もちろん、スクリプト言語を使用してデータベースの外で次の問題に対処することもできますが、扱うデータの量と手動の必要性を排除したいため、それは避けたいと考えています。ステップ。

要するに、リストの表があります。リストは、単一の 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);
001
あ003
004
005
B008
B007
C010
C011
C012
D011
D012
D013
D016
D017
D018
D020

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

4

1 に答える 1

4

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

SQL 自体は、基本的に文字列の分割である、探している基本的な操作を提供しません。これは、自分で作成するか、オンラインで公開されている多くのもののいずれかを使用する必要があることを意味します。

ただし、データに含まれる範囲によって、問題が少し複雑になります。これは、手順が次のようになることを意味します。

  1. データを一時/メモリ テーブルに挿入し、手続き的に反復します (または、カーソルを使用して同じことを行います)。
  2. セット内の各レコードについて、正規化されていない文字列データを抽出し、 で分割し','ます。
  3. 分割データ内の各要素について、それを分割する必要があります('-'範囲要素の場合、単一の結果が返されます)。
  4. 2 番目の分割 ( on '-') で 1 つの結果が得られた場合、それは最終的な宛先に挿入できる単一のレコードです。2 つの結果が得られる場合、それは範囲であり、最初から最後まで (その分割の要素 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
于 2011-02-10T19:26:02.370 に答える