Split column based on ascii value

妖精的绣舞 提交于 2020-01-25 07:05:24

问题


I have a text field in a table that contains a large string, each part of the string that i want to separate is split by a little square.

When searching I found out this could be an ascii value, so i run this

ascii(substring(image_data, 18,1))

which returned 27

How would go about splitting this field into separate fields based on this ascii value?

Thanks in advance, Chris

EDIT: Example of what the data currently looks like. Having the TEXT before the = as the Header would be great if it is possible.

ABS_ID=1234567 PERSON_ID=1234567 PARTY_ID= ABS_D=123 ABS_T= ABS_TYPE_ID=12345 ABS_ED=123456

The ascii values are where the spaces are in the above example of the field data

Example image of the current data

Example of the output im trying to get

UPDATE The code provided below works great for the example i initially given. When implementing it i discovered the Audit string is different depending on the ENTITY_NM

Example HERE


回答1:


Hint: You might want to read "update 3" first :-)

And the most important hint: Do not store data in such a format. If you can change this, you really should...

Now some different approaches:

(And there is hint 3 :-) : Next time please tag with the RDBMS including the version. This makes it easier to help you. Less guessing...)

Try it like this

--First I mock-up your issue by replacing the separating blanks with the 27. Now we see the rectangles you were talking about.

DECLARE @YourString VARCHAR(1000)=REPLACE('ABS_ID=1234567 PERSON_ID=1234567 PARTY_ID= ABS_D=123 ABS_T= ABS_TYPE_ID=12345 ABS_ED=123456',' ',CHAR(27));
SELECT @YourString;

--This is the query (needs v2016+):

SELECT A.[key] AS Position
      ,LEFT(Fragment,PosEqual-1) AS ValueName
      ,SUBSTRING(Fragment,PosEqual+1,1000) AS ValueContent
FROM OPENJSON(CONCAT('["',REPLACE(@YourString,CHAR(27),'","'),'"]')) A
CROSS APPLY(SELECT A.[value] AS Fragment
                  ,CHARINDEX('=',A.[value]) AS PosEqual) B;

The result

Position    ValueName   ValueContent
0           ABS_ID      1234567
1           PERSON_ID   1234567
2           PARTY_ID    
3           ABS_D       123
4           ABS_T   
5           ABS_TYPE_ID 12345
6           ABS_ED      123456

The idea in short:

Better than STRING_SPLIT() is a JSON-hack, as the first is not position safe.

Using some simple string methods we can transform your separated string in a JSON array. This array we open using OPENJSON(). This method returns the position as key and the fragment as value.

The APPLY will search for the position of the =.

The SELECT will use the position to read the parts left and rigth from the =.

The result is a classical EAV-list.

UPDATE: If you use a version below v2016...

the following query is similiar in principles, but uses a XML-hack and works with versions down to v2005:

SELECT LEFT(C.Fragment,C.PosEqual-1) AS ValueName
      ,SUBSTRING(C.Fragment,C.PosEqual+1,1000) AS ValueContent
FROM (SELECT CAST('<x>'+REPLACE(@YourString,CHAR(27),'</x><x>')+'</x>' AS XML)) A(CastedToXml)
CROSS APPLY A.CastedToXml.nodes('/x') B(xmlFragment)
CROSS APPLY(SELECT B.xmlFragment.value('text()[1]','nvarchar(1000)') AS Fragment
                  ,CHARINDEX('=',B.xmlFragment.value('text()[1]','nvarchar(1000)')) AS PosEqual) C;

UPDATE 2: One more approach

You might split this in one single go like this:

SELECT CAST('<x><y>' + REPLACE(REPLACE(@YourString,'=','</y><y>'),CHAR(27),'</y></x><x><y>') + '</y></x>' AS XML);

Or this:

SELECT CAST('<x name="' + REPLACE(REPLACE(@YourString,'=','">'),CHAR(27),'</x><x name="') + '</x>' AS XML);

The result is this

<x>
  <y>ABS_ID</y>
  <y>1234567</y>
</x>
<x>
  <y>PERSON_ID</y>
  <y>1234567</y>
</x>
<x>
  <y>PARTY_ID</y>
  <y />
</x>
<x>
  <y>ABS_D</y>
  <y>123</y>
</x>
<x>
  <y>ABS_T</y>
  <y />
</x>
<x>
  <y>ABS_TYPE_ID</y>
  <y>12345</y>
</x>
<x>
  <y>ABS_ED</y>
  <y>123456</y>
</x>

Or this:

<x name="ABS_ID">1234567</x>
<x name="PERSON_ID">1234567</x>
<x name="PARTY_ID" />
<x name="ABS_D">123</x>
<x name="ABS_T" />
<x name="ABS_TYPE_ID">12345</x>
<x name="ABS_ED">123456</x>

UPDATE 3 (this should be on top probably :-) )

This will do the pivoting implicitly:

SELECT CastedToXml.value('(/x[@name="ABS_ID"]/text())[1]','bigint') AS ABS_ID
      ,CastedToXml.value('(/x[@name="PERSON_ID"]/text())[1]','bigint') AS PERSON_ID
      ,CastedToXml.value('(/x[@name="PARTY_ID"]/text())[1]','bigint') AS PARTY_ID
      ,CastedToXml.value('(/x[@name="ABS_D"]/text())[1]','bigint') AS ABS_D
      ,CastedToXml.value('(/x[@name="ABS_T"]/text())[1]','bigint') AS ABS_T
      ,CastedToXml.value('(/x[@name="ABS_TYPE_ID"]/text())[1]','bigint') AS ABS_TYPE_ID
      ,CastedToXml.value('(/x[@name="ABS_ED"]/text())[1]','bigint') AS ABS_ED
FROM
(SELECT CAST('<x name="' + REPLACE(REPLACE(@YourString,'=','">'),CHAR(27),'</x><x name="') + '</x>' AS XML)) A(CastedToXml);

The result

ABS_ID  PERSON_ID   PARTY_ID    ABS_D   ABS_T   ABS_TYPE_ID ABS_ED
1234567 1234567     NULL        123     NULL    12345       123456


来源:https://stackoverflow.com/questions/58856050/split-column-based-on-ascii-value

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!