web-dev-qa-db-fra.com

Comment fractionner une valeur de chaîne en fonction d'un délimiteur dans DB2

Comment diviser une valeur de chaîne dans DB2? 

Par exemple, étant donné la valeur: 

CHG-FFH.

Je veux diviser sur le tiret (-), ce qui donnerait deux valeurs:

CHG 
FFH. 

J'ai essayé d'utiliser la fonction split, mais ce n'est pas une fonction dans DB2. 

Toute aide serait appréciée.

5
sTg

C'est ce que j'ai essayé et cela m'a apporté un résultat efficace. Partage avec tous.

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

Réponse courte:  

Vous devez trouver la position du délimiteur , Puis une sous-chaîne avant et après.

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;

Réponse longue:  

DB2, ainsi que d'autres bases de données relationnelles, ne fournit pas une seule fonction pour accomplir cela. 

La raison en est probablement que ce n'est pas une fonction implicitement scalaire. Si votre chaîne avait plus d'un tiret, voudriez-vous la scinder en trois parties? Quatre? La première étape consiste donc à noter si vos données sont déterminées - si elles contiennent un nombre spécifique de composants que vous souhaitez séparer. Dans votre exemple, vous en avez deux, je vais donc commencer par cette hypothèse, puis par la suite, nous expliquerons comment vous feriez face à d'autres situations. 

Scénario: Une valeur de chaîne avec deux composants séparés par un délimiteur

Avec seulement deux parties, vous devez trouver la position du délimiteur, puis la sous-chaîne avant et après en utilisant la position avant et après dans une fonction de sous-chaîne. 

  1. LOCALISEl'index de votre délimiteur. 
LOCATE('-','CHG-FFH')

REMARQUE: DB2 fournit deux fonctions utilisables à cet effet: POSITION (ou POSSTR) et LOCALISE. _ (ou LOCATE_IN_STRING).LOCALISEest un peu plus puissant car il vous permet de spécifier une position de départ, ce qui serait utile si vous aviez plusieurs délimiteurs.

  1. SUBSTRen utilisant l'index de délimiteur. 

Pour la première partie, commencez votre sous-chaîne en position 1, jusqu'au caractère situé avant le délimiteur (position du délimiteur - 1): 

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

Pour la deuxième partie, démarrez votre sous-chaîne à la position après l'index du délimiteur (position du délimiteur + 1) et obtenez le reste de la chaîne: 

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

Résultat final:  

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;

Scénario: Une valeur de chaîne avec trois composants séparés par un délimiteur

Utilisez les mêmes concepts que dans le premier scénario, mais vous devez déterminer l'index du deuxième délimiteur. Utilisez l'index du premier délimiteur pour spécifier un point de départ: Notez queLOCALISEpermet de spécifier une position de départ: 

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

Recherche du deuxième délimiteur:  

Utilisez la position du premier délimiteur comme point de départ pour rechercher le deuxième délimiteur. 

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

Utilisez-le comme point SUBSTR pour les deuxième et troisième valeurs et vous êtes prêt. Remarque: pour la deuxième valeur, vous devez utiliser les deux emplacements de délimiteur pour sous-chaîne de la valeur. 

Résultat final:  

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;

Vous pouvez voir que cette stratégie deviendrait incontrôlable pour un plus grand nombre de délimiteurs dans votre chaîne. 

Scénario: Nombre indéterminé de délimiteurs

C'est un problème épineux qu'il vaut mieux aborder avec une procédure stockée. Réfléchissez à des choses comme: comment voulez-vous que les données analysées sortent de l'algorithme, comment allez-vous accéder à ces données? Les tableaux ne sont pas un type natif dans SQL, mais dans les procédures stockées. Que ferez-vous avec le tableau lorsque vous aurez analysé tous les éléments de votre chaîne? 

Une façon d'aborder ce scénario est traitée ici: 

Fractionner un VARCHAR dans DB2 pour récupérer une valeur à l'intérieur

16
Josh Hull

Essayez cette déclaration:

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

Je sais que c’est un vieux message .. mais penser que cela peut aider les autres.

J'ai utilisé l'approche suivante pour diviser la chaîne donnée.

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

Dans 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;

Continuez à extrapoler ... profitez ...

0
Vikram Vedha

Si vous êtes certain que chaque sous-chaîne a 3 caractères, vous pouvez essayer ce code, à condition que TABLE1 soit une table contenant au moins X lignes (X = 10 dans cet exemple):

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) <> '   '

Si la longueur des sous-chaînes n'est pas la même, vous devez appliquer la fonction LOCATE pour trouver le séparateur.

0
Otto

J'avais besoin d'utiliser instr, substr, trim, et joué avec localiser aussi .. mais instr, et substr sont tous supportés. Vous pouvez trouver un motif. Je devais passer par un varchar divisé avec '-' et devais trouver la fin et revenir de là.

           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