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.
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 '%-%'
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.
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.
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
Essayez cette déclaration:
select substr(your_value, 1,3), substr(your_value, 4, 3) from your_table
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;
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 ...
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.
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