Extract data from one column of SQL Server table I have an SQL Server table from which I want to extract data from one column (DD) and return as multiple columns.

The data is in NVARCHAR and looks like:


  ;&lt;b&gt;HF&lt;/b&gt;:GN;&lt;b&gt;HM&lt;/b&gt;:GTN;&lt;b&gt;HN&lt;/b&gt;:GN;&lt;b&gt;PN&lt;/b&gt;:AN;&lt;b&gt;PVD&lt;/b&gt;:GO;&lt;b&gt;PVR&lt;/b&gt;:1.1;&lt;b&gt;BN&lt;/b&gt;:AN;&lt;b&gt;BVD&lt;/b&gt;:GO;&lt;b&gt;BV&lt;/b&gt;:2.3;


There is less to be changed in the way this data is structured.

I have to extract all of the data in &lt;b&gt;...&lt;/b&gt; and between : and ; and have to return as individual columns. I tried with the following query:

SELECT DataID
    ,SUBSTRING(DD,CHARINDEX(';&lt;b&gt;HF&lt;/b&gt;:',DD) + LEN(';&lt;b&gt;HF&lt;/b&gt;:'),CHARINDEX(';&lt;b&gt;HM&lt;/b&gt;:',DD) - (CHARINDEX(';&lt;b&gt;HF&lt;/b&gt;:',DD) + LEN(';&lt;b&gt;HF&lt;/b&gt;:'))) as HF
    ,SUBSTRING(DD,CHARINDEX(';&lt;b&gt;HM&lt;/b&gt;:',DD) + LEN(';&lt;b&gt;HM&lt;/b&gt;:'),CHARINDEX(';&lt;b&gt;HN&lt;/b&gt;:',DD) - (CHARINDEX(';&lt;b&gt;HM&lt;/b&gt;:',DD) + LEN(';&lt;b&gt;HM&lt;/b&gt;:'))) as HM
    ,SUBSTRING(DD,CHARINDEX(';&lt;b&gt;HN&lt;/b&gt;:',DD) + LEN(';&lt;b&gt;HN&lt;/b&gt;:'),CHARINDEX(';&lt;b&gt;PN&lt;/b&gt;:',DD) - (CHARINDEX(';&lt;b&gt;HN&lt;/b&gt;:',DD) + LEN(';&lt;b&gt;HN&lt;/b&gt;:'))) as HN
    ,SUBSTRING(DD,CHARINDEX(';&lt;b&gt;PN&lt;/b&gt;:',DD) + LEN(';&lt;b&gt;PN&lt;/b&gt;:'),CHARINDEX(';&lt;b&gt;PVD&lt;/b&gt;:',DD) - (CHARINDEX(';&lt;b&gt;PN&lt;/b&gt;:',DD) + LEN(';&lt;b&gt;PN&lt;/b&gt;:'))) as PN
    ,SUBSTRING(DD,CHARINDEX(';&lt;b&gt;PVD&lt;/b&gt;:',DD) + LEN(';&lt;b&gt;PVD&lt;/b&gt;:'),CHARINDEX(';&lt;b&gt;PVR&lt;/b&gt;:',DD) - (CHARINDEX(';&lt;b&gt;PVD&lt;/b&gt;:',DD) + LEN(';&lt;b&gt;PVD&lt;/b&gt;:'))) as PVD
    ,SUBSTRING(DD,CHARINDEX(';&lt;b&gt;PVR&lt;/b&gt;:',DD) + LEN(';&lt;b&gt;PVR&lt;/b&gt;:'),CHARINDEX(';&lt;b&gt;BN&lt;/b&gt;:',DD) - (CHARINDEX(';&lt;b&gt;PVR&lt;/b&gt;:',DD) + LEN(';&lt;b&gt;PVR&lt;/b&gt;:'))) as PVR
    ,SUBSTRING(DD,CHARINDEX(';&lt;b&gt;BN&lt;/b&gt;:',DD) + LEN(';&lt;b&gt;BN&lt;/b&gt;:'),CHARINDEX(';&lt;b&gt;BVD&lt;/b&gt;:',DD) - (CHARINDEX(';&lt;b&gt;BN&lt;/b&gt;:',DD) + LEN(';&lt;b&gt;BN&lt;/b&gt;:'))) as BN
    ,SUBSTRING(DD,CHARINDEX(';&lt;b&gt;BVD&lt;/b&gt;:',DD) + LEN(';&lt;b&gt;BVD&lt;/b&gt;:'),CHARINDEX(';&lt;b&gt;BVR&lt;/b&gt;:',DD) - (CHARINDEX(';&lt;b&gt;BVD&lt;/b&gt;:',DD) + LEN(';&lt;b&gt;BVD&lt;/b&gt;:'))) as BVD
    ,SUBSTRING(DD,CHARINDEX(';&lt;b&gt;BVR&lt;/b&gt;:',DD) + LEN(';&lt;b&gt;BVR&lt;/b&gt;:'),LEN(DD) - (CHARINDEX(';&lt;b&gt;BVR&lt;/b&gt;:',DD) + LEN(';&lt;b&gt;BVR&lt;/b&gt;:'))) as BVR
FROM DataTable
WHERE DD is not null


I think I'll have to generate the query at run-time from a list of column names or may have hard-coded query as the structure of the data and the required columns is not likely to change.

Given that, is there a better approach to optimize this query? May be by using Regular Expressions or any other approach?

Edit:

Is there a better approach using C# Code-behind? This eventually is being used for an ASP.Net Web Application.
Basically, sql is not meant to parse text.  The database design is the issue here and it probably needs to be modified.  Another option is to return the string to the server and do the parsing there and then make another call to sql.

My answer is basically a copy of Andrew White's answer to this stackoverflow question.