Home > Back-end >  SQL extracting data from 1 string / SWIFT message
SQL extracting data from 1 string / SWIFT message

Time:12-10

I have a whole SWIFT message with fees in one "cell" as SwiftMessage.Body. So the whole message is in one string. What I need to do is, extract certain data from it. Using SSRS and MS SQL The message looks something like this:

.....(FEE 1)
:20C::PCOM//C22033100734330
:20C::PREF//FC22033100734330
:22H::PNTP//SEFP
:24B::ACTV//NEWP
:19A::AMCO//NEUR50
:99A::DAAC//001
.....(FEE 2)
:20C::PCOM//C22033100734331
:20C::PREF//FC22033100734331
:22H::PNTP//SEFP
:24B::ACTV//NEWP
:19A::AMCO//EUR40
:99A::DAAC//002
.....(FEE n)

there can be any number of fees, not just 2

The result should be extracting :20C::PREF// and :19A::AMCO//:

ID Amount
FC22033100734330 -50
FC22033100734331 40

what I have right now

SELECT
SUBSTRING(swf.SwiftMessage.Body, (CHARINDEX(':20C::PREF', swf.SwiftMessage.Body)   12)
, CHARINDEX(':22H::PNTP',swf.SwiftMessage.Body) - CHARINDEX(':20C::PREF', swf.SwiftMessage.Body) - 12) as REF1,
SUBSTRING(swf.SwiftMessage.Body, (CHARINDEX(':19A::AMCO', swf.SwiftMessage.Body)   12)
, CHARINDEX(':99A::DAAC',swf.SwiftMessage.Body) - CHARINDEX(':19A::AMCO', swf.SwiftMessage.Body) - 12) as AMT
 

FROM
  swf.SwiftMessage

so with this I am somehow able to extract data I need (the amount is in format currency amt which I can deal with later hopefuly). The main problem right now is how to deal with the fact, that there might be more fees, than just one so I need to make some kind of a loop? that will go through the whole string and find every :20C::PREF// and :19A::AMCO// values.

CodePudding user response:

First of all, I would suggest doing this splitting at a different place, either when inserting the data into the database, or after retrieving it, perhaps using the language that the program used to communicate with the DB.

If you really must do the splitting using SQL alone, you have a few options to loop over the Data. They either use Recursion, classic WHILE loops or use the STRING_SPLIT function, as mentioned in this post.

If you happen to use SQL Server 2016 or later, I suggest you use STRING_SPLIT, something along the lines of

SELECT value FROM STRING_SPLIT('.....(FEE 1):20C::PCOM//C22033100734330:20C::PREF//FC22033100734330:22H::PNTP//SEFP:24B::ACTV//NEWP:19A::AMCO//NEUR50:99A::DAAC//001.....(FEE 2):20C::PCOM//C22033100734331:20C::PREF//FC22033100734331:22H::PNTP//SEFP:24B::ACTV//NEWP:19A::AMCO//EUR40:99A::DAAC//002.....(FEE n)', ':99A::DAAC');

this together with CROSS APPLY whould get you a whole step closer to parsing the data for each message:

SELECT value FROM swf.SwiftMessage CROSS APPLY STRING_SPLIT(Body,':99A::DAAC')

then just substring each value

CodePudding user response:

Here is an option which parses the string via JSON to maintain the SEQUENCE. Then it becomes a small matter of a conditional aggregation

Note: this is keyed on EUR. If you have other currencies, it would be a small tweak

Example

Declare @S varchar(max)='.....(FEE 1)
:20C::PCOM//C22033100734330
:20C::PREF//FC22033100734330
:22H::PNTP//SEFP
:24B::ACTV//NEWP
:19A::AMCO//NEUR50
:99A::DAAC//001
.....(FEE 2)
:20C::PCOM//C22033100734331
:20C::PREF//FC22033100734331
:22H::PNTP//SEFP
:24B::ACTV//NEWP
:19A::AMCO//EUR40
:99A::DAAC//002'

Select ID  = max( case when value like ':20C::PREF//%' then substring(value,13,100) end)
      ,Amt = max( case when value like ':19A::AMCO//%' then try_convert(decimal(15,4),replace(replace(substring(value,13,100),'NEUR','-'),'EUR','')) end)
 From  (
        Select *
              ,Grp = sum( case when value like '.....(FEE%' then 1 end ) over (order by convert(int,[key]))
         From  OpenJSON( '["' replace(string_escape(replace(@S,char(13) char(10),'|||'),'json'),'|||','","') '"]' )
       ) A
 Group By Grp

Results

ID                  Amt
FC22033100734330    -50.0000
FC22033100734331    40.0000

CodePudding user response:

Give this a try:

DECLARE @swifty NVARCHAR(MAX) = '.....(FEE 1)
:20C::PCOM//C22033100734330
:20C::PREF//FC22033100734330
:22H::PNTP//SEFP
:24B::ACTV//NEWP
:19A::AMCO//NEUR50
:99A::DAAC//001
.....(FEE 2)
:20C::PCOM//C22033100734331
:20C::PREF//FC22033100734331
:22H::PNTP//SEFP
:24B::ACTV//NEWP
:19A::AMCO//EUR40
:99A::DAAC//002
.....(FEE 3)
:20C::PCOM//C22033100734332
:20C::PREF//FC22033100734332
:22H::PNTP//SEFP
:24B::ACTV//NEWP
:19A::AMCO//USD9999
:99A::DAAC//001
.....(FEE 4)
:20C::PCOM//C22033100734333
:20C::PREF//FC22033100734333
:22H::PNTP//SEFP
:24B::ACTV//NEWP
:19A::AMCO//GBP1
:99A::DAAC//001
.....(FEE 5)
:20C::PCOM//C22033100734334
:20C::PREF//FC22033100734334
:22H::PNTP//SEFP
:24B::ACTV//NEWP
:19A::AMCO//NGBP300
:99A::DAAC//001
.....(FEE 6)
:20C::PCOM//C22033100734335
:20C::PREF//FC22033100734335
:22H::PNTP//SEFP
:24B::ACTV//NEWP
:19A::AMCO//NUSD325412254
:99A::DAAC//001
'

SELECT FeeID,  
MAX(CASE WHEN value LIKE CHAR(10) ':20C::PREF//%' THEN SUBSTRING(value,CHARINDEX('//',value) 2,LEN(value)) END) AS ID,
MAX(CASE WHEN value LIKE CHAR(10) ':19A::AMCO//N%'    THEN SUBSTRING(value,CHARINDEX('//',value) 3,3)
         WHEN value LIKE CHAR(10) ':19A::AMCO//[^N]%' THEN SUBSTRING(value,CHARINDEX('//',value) 2,3) END) AS Currency,
MAX(CASE WHEN value LIKE CHAR(10) ':19A::AMCO//N%'    THEN SUBSTRING(value,CHARINDEX('//',value) 6,LEN(value))*-1
         WHEN value LIKE CHAR(10) ':19A::AMCO//[^N]%' THEN SUBSTRING(value,CHARINDEX('//',value) 5,LEN(value)) END) AS Fee
  FROM (
        SELECT Value, ((ROW_NUMBER() OVER (ORDER BY (SELECT 1))-1) / 7) 1 AS FeeID
          FROM STRING_SPLIT(@swifty,CHAR(13))
       ) A
 WHERE value LIKE CHAR(10) ':19A::AMCO//%'
    OR value LIKE CHAR(10) ':20C::PREF//%'
 GROUP BY FeeID

This shouldn't be reliant on the values being in any specific format or type, just that they are referenced as :19A:: and :20C::

FeeID   ID                  Currency    Fee
-------------------------------------------
1       FC22033100734330    EUR         -50
2       FC22033100734331    EUR         40
3       FC22033100734332    USD         9999
4       FC22033100734333    GBP         1
5       FC22033100734334    GBP         -300
6       FC22033100734335    USD         -325412254
  • Related