13

DB2 で文字列値をどのように分割しますか?

たとえば、次の値があるとします。

CHG-FFH.

ダッシュ (-) で分割すると、次の 2 つの値になります。

CHG 
FFH. 

分割関数を使用してみましたが、DB2 の関数ではありません。

どんな助けでも大歓迎です。

4

11 に答える 11

30

簡潔な答え:

区切り文字の位置を見つけ、それを開始点として使用する部分文字列と計算された長さを見つける必要があります。

SELECT 
    SUBSTR('CHG-FFH', 1, LOCATE('-','CHG-FFH')-1) as FIRST_PART
  , SUBSTR('CHG-FFH', LOCATE('-','CHG-FFH')+1)   as SECOND_PART
FROM SYSIBM.SYSDUMMY1;

ボーナス!これを頻繁に行う場合は、ユーザー定義関数を作成して動的に実行します。DBフィドルの例を次に示します。

CREATE FUNCTION SPLITTER (input VARCHAR(4000), delimiter CHAR, part_number INTEGER)
      RETURNS VARCHAR(4000)
      LANGUAGE SQL
      READS SQL DATA
      NO EXTERNAL ACTION
      DETERMINISTIC
      RETURN 

with pos_info (first_pos, length) as (
select 
  case when part_number = 1 then 0
       else LOCATE_IN_STRING(input, delimiter,1, part_number-1, OCTETS)  
  end as first_pos, 

  case when part_number = 1 then LOCATE_IN_STRING(input, delimiter,1, part_number, OCTETS) - 1 
       when LOCATE_IN_STRING(input, delimiter,1, part_number, OCTETS) = 0
        and  LOCATE_IN_STRING(input, delimiter,1, part_number-1, OCTETS) = 0
       then 0
       when LOCATE_IN_STRING(input, delimiter,1, part_number, OCTETS) = 0
       then length(input) -  LOCATE_IN_STRING(input, '-',1, part_number - 1,    OCTETS)
       else LOCATE_IN_STRING(input, delimiter,1, part_number, OCTETS) -    LOCATE_IN_STRING(input, delimiter,1, part_number-1, OCTETS) - 1
  end as length
from sysibm.sysdummy1
)

select    
    substr(input, first_pos+1,length) as part
from pos_info;

または、この回答で別のアプローチを見ることができます: Split a VARCHAR in DB2 to retrieve a value inside 。


長い答え:

DB2 は、他のリレーショナル データベースと同様に、これを実現する単一の機能を提供していません。

その理由は、暗黙のスカラー関数ではない可能性があります。文字列に複数のダッシュが含まれている場合、それを 3 つの部分に分割しますか? 四?したがって、最初のステップは、データが決定的であるかどうか、つまり分割したい特定の数のコンポーネントがあるかどうかに注意することです。あなたの例では、2 つあるので、その仮定から始めて、その後、他の状況にどのように対処するかについてコメントします。

シナリオ: 区切り文字で区切られた 2 つのコンポーネントを持つ文字列値

2 つの部分しかない場合は、区切り記号の位置を見つけてから、その前後の位置を部分文字列関数で使用してその前後の部分文字列を見つける必要があります。

  1. 区切り文字のインデックスを見つけます。
LOCATE('-','CHG-FFH')

注: DB2 は、これに使用できる 2 つの関数を提供します: POSITION (または POSSTR) とLOCATE (または LOCATE_IN_STRING)。LOCATEは、開始位置を指定できるため、もう少し強力です。これは、区切り文字が複数ある場合に役立ちます。

  1. デリミタ インデックスを使用した SUBSTR 。

最初の部分では、部分文字列を位置 1 から開始し、区切り記号の前の文字まで (区切り記号の位置 - 1):

SUBSTR('CHG-FFH', 1,LOCATE('-','CHG-FFH')-1) as FIRST_PART

2 番目の部分では、区切り記号のインデックスの後の位置 (区切り記号の位置 + 1) で部分文字列を開始し、残りの文字列を取得します。

 SUBSTR('CHG-FFH', LOCATE('-','CHG-FFH')+1) as SECOND_PART

最終結果:

SELECT 
    SUBSTR('CHG-FFH', 1,LOCATE('-','CHG-FFH')-1) as FIRST_PART
  , SUBSTR('CHG-FFH', LOCATE('-','CHG-FFH')+1) as SECOND_PART
FROM SYSIBM.SYSDUMMY1;

シナリオ: 区切り文字で区切られた 3 つのコンポーネントを持つ文字列値

最初のシナリオと同じ概念を使用しますが、2 番目の区切り文字のインデックスを決定する必要があります。最初の区切り文字のインデックスを使用して開始点を指定します。LOCATEを使用すると開始位置を指定できることに注意してください。

>>-LOCATE(search-string,source-string-+--------+-+--------------------+-)-><
                                      '-,start-' '-,--+-CODEUNITS16-+-'     
                                                      +-CODEUNITS32-+       
                                                      '-OCTETS------' 

2 番目の区切り文字を見つける:

2 番目の区切り記号を見つけるための開始点として、最初の区切り記号の位置を使用します。

LOCATE('-','CHG-FFH-EEE', LOCATE('-','CHG-FFH-EEE')+1)

これを 2 番目と 3 番目の値の SUBSTR ポイントとして使用すれば、準備完了です。注: 2 番目の値については、両方の区切り文字の場所を使用して値を部分文字列にする必要があります。

最終結果:

SELECT 
    SUBSTR('CHG-FFH-EEE', 1,LOCATE('-','CHG-FFH-EEE')-1) as FIRST_PART
  , SUBSTR('CHG-FFH-EEE', LOCATE('-','CHG-FFH-EEE')+1, LOCATE('-','CHG-FFH-EEE', LOCATE('-','CHG-FFH-EEE'))-1) as SECOND_PART
  , SUBSTR('CHG-FFH-EEE', LOCATE('-','CHG-FFH-EEE', LOCATE('-','CHG-FFH-EEE')+1)+1) as THIRD_PART
FROM SYSIBM.SYSDUMMY1;

この戦略は、文字列内の区切り文字の数が多いと手に負えなくなることがわかります。

シナリオ: 区切り文字の数が不確定

これは、ストアド プロシージャを使用して対処するのが最適なトリッキーな問題です。次のようなことを考えてみてください: 解析されたデータをアルゴリズムからどのように取得するか、データにどのようにアクセスしますか? 配列は SQL のネイティブ型ではありませんが、ストアド プロシージャには含まれているため、文字列からすべての部分を解析したら、配列をどうしますか?

このシナリオにアプローチする 1 つの方法は、次のとおりです。

DB2 で VARCHAR を分割して内部の値を取得する

于 2013-09-23T16:00:43.637 に答える
0

各部分文字列の長さが 3 文字であることが確実な場合は、TABLE1 が少なくとも X 行 (この例では X = 10) があるテーブルであるという条件で、このコードを試すことができます。

select rc, substr(string_to_split, (rc-1)*3+rc, 3) as result from
    (select row_number() over() as rc from TABLE1 fetch first 10 rows only) TB_rowcount
    cross join
    (select 'CHG-FFH' as string_to_split from sysibm.sysdummy1) T2
    where substr(string_to_split, (rc-1)*3+rc, 3) <> '   '

部分文字列の長さが同じでない場合は、LOCATE関数を適用してセパレータを見つける必要があります

于 2015-12-31T13:41:36.937 に答える