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 searchin
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.
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(''+REPLACE(@YourString,CHAR(27),' ')+' ' 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;
You might split this in one single go like this:
SELECT CAST('' + REPLACE(REPLACE(@YourString,'=',' '),CHAR(27),' ') + ' ' AS XML);
Or this:
SELECT CAST(''),CHAR(27),' 1234567
1234567
123
12345
123456
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(''),CHAR(27),'