简体   繁体   English

SQL 从 1 个字符串中提取数据 / SWIFT 消息

[英]SQL extracting data from 1 string / SWIFT message

I have a whole SWIFT message with fees in one "cell" as SwiftMessage.Body.我有一个完整的 SWIFT 消息,在一个“单元格”中作为 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:使用 SSRS 和 MS SQL 消息看起来像这样:

.....(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可以有任意数量的费用,而不仅仅是 2

The result should be extracting:20C::PREF// and:19A::AMCO//:结果应该是提取:20C::PREF// 和:19A::AMCO//:

ID ID Amount数量
FC22033100734330 FC22033100734330 -50 -50
FC22033100734331 FC22033100734331 40 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).因此,我以某种方式能够提取我需要的数据(金额采用货币+amt 格式,我希望以后可以处理)。 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.这将 go 通过整个字符串并找到每个:20C::PREF// 和:19A::AMCO// 值。

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.如果您真的必须单独使用 SQL 进行拆分,您有几个选项可以循环数据。 They either use Recursion, classic WHILE loops or use the STRING_SPLIT function, as mentioned in this post .他们要么使用递归、经典的WHILE循环,要么使用STRING_SPLIT function,如本文所述。

If you happen to use SQL Server 2016 or later, I suggest you use STRING_SPLIT , something along the lines of如果您碰巧使用 SQL Server 2016 或更高版本,我建议您使用STRING_SPLIT ,类似于

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:这与CROSS APPLY一起将使您更接近于解析每条消息的数据:

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

then just substring each value那么每个值只有 substring

Here is an option which parses the string via JSON to maintain the SEQUENCE.这是一个通过 JSON 解析字符串以维护 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

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::这不应该依赖于任何特定格式或类型的值,只是它们被引用为:19A:::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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM