web-dev-qa-db-ja.com

DB2で区切り文字に基づいて文字列値を分割する方法

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

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

CHG-FFH.

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

CHG 
FFH. 

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

どんな助けでもありがたいです。

7
sTg

これは私が試したものであり、それは私に効果的な結果をもたらしました。したがって、すべてと共有します。

select column_name, substr(column_name,1,locate('-',column_name)-1), 
substr(column_name,locate('-',column_name)+1,
length(substr(column_name,locate('-',column_name)+1))) from 
table_name where column_name is not null and column_name!='' 
and column_name like '%-%'
3
sTg

短い答え:

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

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;

BONUS!これを頻繁に行う場合は、ユーザー定義関数を作成して動的に実行します。これが 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;

または別のアプローチを見ることができます この回答:DB2でVARCHARを分割して内部の値を取得する


長い答え:

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

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

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

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

  1. [〜#〜] locate [〜#〜]区切り文字のインデックス。
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を分割します

21
Josh Hull

このステートメントを試してください:

select substr(your_value, 1,3), substr(your_value, 4, 3) from your_table
2
Peter Miehle

私はこれが古い記事であることを知っています。

以下のアプローチを使用して、指定された文字列を分割しました。

SELECT TRIM(ITEM) AS ITEM FROM TABLE(<LIB1>.SF_SPLIT(I_INPUTLIST=>'AA|BB|CC|DD|EE|EE|FF', I_DELIMITER=>'|')) AS T;

SF_SPLIT is the User defined SQL function and below is definition:

CREATE OR REPLACE FUNCTION <LIB1>.SF_SPLIT(

    I_INPUTLIST VARCHAR(8000) 
  , I_DELIMITER VARCHAR(3)    

) 
RETURNS TABLE (ITEM VARCHAR(8000))

LANGUAGE SQL

RETURN

WITH R1 (ITEM, REMINDER) AS 

(SELECT SUBSTR(I_INPUTLIST, 1, LOCATE(I_DELIMITER, I_INPUTLIST)-1) AS ITEM, 

SUBSTR(I_INPUTLIST, LOCATE(I_DELIMITER, I_INPUTLIST)+1, LENGTH(I_INPUTLIST)) REMINDER

FROM SYSIBM.SYSDUMMY1

UNION ALL

SELECT SUBSTR(REMINDER, 1, LOCATE(I_DELIMITER, REMINDER)-1) AS ITEM, 
SUBSTR(REMINDER, LOCATE(I_DELIMITER, REMINDER)+1, LENGTH(REMINDER)) REMINDER 

FROM R1 WHERE LOCATE(I_DELIMITER, REMINDER) > 0

UNION ALL

SELECT SUBSTR(REMINDER, LOCATE(I_DELIMITER, REMINDER)+1, LENGTH(REMINDER)) AS ITEM,

'' AS REMINDER FROM R1 WHERE REMINDER <> '' AND LOCATE(I_DELIMITER, REMINDER) = 0

)

SELECT ITEM FROM R1;
0
Jai

DB2内

SELECT
'11,222,33,444' AS THE_F_STRING
, SUBSTR('11,222,33,444', 1, LOCATE_IN_STRING('11,222,33,444',',',1,1)-1) AS AA
, SUBSTR('11,222,33,444', LOCATE_IN_STRING('11,222,33,444',',',1,1)+1, LOCATE_IN_STRING('11,222,33,444',',',1,2)-LOCATE_IN_STRING('11,222,33,444',',',1,1)-1) AS BB 
, SUBSTR('11,222,33,444', LOCATE_IN_STRING('11,222,33,444',',',1,2)+1, LOCATE_IN_STRING('11,222,33,444',',',1,3)-LOCATE_IN_STRING('11,222,33,444',',',1,2)-1) AS CC
, SUBSTR('11,222,33,444', LOCATE_IN_STRING('11,222,33,444',',',1,3)+1, LENGTH('11,222,33,444')-LOCATE_IN_STRING('11,222,33,444',',',1,3)) AS DD
FROM SYSIBM.SYSDUMMY1;

外挿してください...お楽しみください...

0
Vikram Vedha

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

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関数を適用してセパレータを見つける必要があります

0
Otto

私はinstr、substr、trimを使用する必要があり、locateもいじりました。しかし、instrとsubstrはすべてサポートされています。パターンを見つけることができます。 「-」でvarchar分割を実行する必要があり、最後を見つけてそこから戻る必要がありました。

           select  itn, 
           substr(Message, 1 , locate(' - ', Message)) FIRST_SSR,  
           SUBSTR(Message , instr( message, ' - ', octets)+1, (instr( 
            message, '(Ref', octets)+1)) SECOND_STR ,
           Message
              from
         (
   select p.itn itn, 
          substr(p.msg,  instr( p.msg, ' - ' , octets)+21) Message
    from itnpad p
    where p.msg like '%MR - Multiple Requests%'

       ) A 
0
David Isser