Solved

SQL Server - how to parse data from a single column into separate columns TAB Delimited

Posted on 2016-08-31
10
51 Views
Last Modified: 2016-09-04
My data table looks like this:

RowID      DetailData
1      0BATCH NEXTGEN         NEXTGENEMR 20160829CPM         651
2      1P0007.63579.0000                           1609168541          899972053           1230                                  CN25
3      2P201608232016082399348            1   0         1
4      51 401.9
5      52 719.45
6      71609168541
7      1P0007.63512.0000                           1093765679          100458751           1230                                  CN25
8      2P201608262016082699347            1   0         1
9      51 787.01
10      71093765679
11      1P0014.236945.0000                          1174807291          2254912701          1230                                  GW23
12      2P201608252016082599341            1   0         1
13      51 402.10
14      52 272.2
15      53 250.00
16      54 244.9
17      55 414.01
18      56 278.02
19      57 V85.24
20      71174807291

The Detailed Data column needs to be separated into separate COLUMNS of data based on the TAB spacing.

Each Full Record contains Rows that start with "1,2,5 and 7". I believe there can be 1 or many rows for each "1,2,5,7" but it appears that most multiple rows show up in the "5" type.

I need help in creating a sql script that will step through this table and separate the DetailedData field into separate fields.

Thanks
0
Comment
Question by:MIKE
  • 5
  • 4
10 Comments
 
LVL 69

Accepted Solution

by:
ScottPletcher earned 250 total points
ID: 41778311
Use a splitter function.  dbo.DelimitedSplit8K is excellent, you can Google for its source code.

SELECT mt.RowID,
    MAX(CASE WHEN ds.ItemNumber = 1 THEN ds.Item END) AS Column1,
    MAX(CASE WHEN ds.ItemNumber = 2 THEN ds.Item END) AS Column2,
    MAX(CASE WHEN ds.ItemNumber = 3 THEN ds.Item END) AS Column3,
    MAX(CASE WHEN ds.ItemNumber = 4 THEN ds.Item END) AS Column4 --,...
FROM dbo.main_table mt
CROSS APPLY dbo.DelimitedSplit8K (mt.DetailData, CHAR(9)) ds
GROUP BY mt.RowID
0
 
LVL 17

Author Comment

by:MIKE
ID: 41778809
Thanks for the input.

Can this be used with a "tab delimited" source field?

The documentation states that it is specifically coded for a "Single Character Delimiter", change at your own risk...
0
 
LVL 69

Expert Comment

by:ScottPletcher
ID: 41778829
Yeah, but a tab is a single character delimiter.  CHAR(9) iirc.
0
 
LVL 17

Author Comment

by:MIKE
ID: 41778892
What I'm really looking for as a result is this:

For example, for ROWID 1-6, I need to take that "DetailData" field for each ROWID and parse it out into a single FLAT ROW.

This should be the result for the RowIDs 1-6 should be:

col1,col2,col3,col4,col5,col6,col7,col8,col9,col10,col11,col12
P0007.63579.0000,1609168541,899972053,1230,CN25,P201608232016082399348,1,0,1,401.9,719.45,1609168541
0
 
LVL 69

Expert Comment

by:ScottPletcher
ID: 41778907
I can't provide exact code for that since I don't have ready-to-use data.  But I think a combination of ROW_NUMBER() and the split could be made to work.
0
Zoho SalesIQ

Hassle-free live chat software re-imagined for business growth. 2 users, always free.

 
LVL 17

Author Comment

by:MIKE
ID: 41778991
Here is the data sample:

rowid,detaildata
1,      0BATCH NEXTGEN         NEXTGENEMR 20160829CPM         651
2,      1P0007.63579.0000                           1609168541          899972053           1230                                  CN25
3,      2P201608232016082399348            1   0         1
4,      51 401.9
5,      52 719.45
6,      71609168541
7,      1P0007.63512.0000                           1093765679          100458751           1230                                  CN25
8,      2P201608262016082699347            1   0         1
9,      51 787.01
10,      71093765679
11,      1P0014.236945.0000                          1174807291          2254912701          1230                                  GW23
12,      2P201608252016082599341            1   0         1
13,      51 402.10
14,      52 272.2
15,      53 250.00
16,      54 244.9
17,      55 414.01
18,      56 278.02
19,      57 V85.24
20,      71174807291
0
 
LVL 69

Expert Comment

by:ScottPletcher
ID: 41779873
I don't have time to convert that splat of data into create table and insert statements.  that takes more time -- and is far more boring -- than writing the final query.
0
 
LVL 1

Assisted Solution

by:Brad Featherstone
Brad Featherstone earned 250 total points
ID: 41781821
This sorta look like a debug/telemetry feed from a device. A proposed solution is attached.

Nauseating Detail
You have an ordered set of input records that are individually typed. The input set is structured, a single unit starts with a Type 1 record. It looks like Type 1, 2, and 7 are always present. The unit may contain one or more type 5 records.

I ignored the record ids that you provided because it makes for a more generic solution.

So the problems are:
1) Create formal record types
2) Formally associate the records of a unit
3) Create a single record from the unit.

First create the dummy data set/feed.
Then, create an internal table to hold the data and associated row and unit identities within the procedure.  I used a table variable.

Problem 1 - Create formal record types
Easy peasy - Strip the first byte off of data and call it record type.  Also individually id each record while jamming it into internal table.

Problem 2 - Formally associate the records of a unit
Find each Type 1 record id and give it a unique rnum identity (ROW_NUMBER() function)
Self join the result to itself by rnum of current record + 1 = next rnum yielding a pair of preceding and following Type 1 record pairs.  Jigger the results to account for NULL in last pair and use of inclusive BETWEEN logic in update. Once the unit ids (GroupId) are assigned, the row ids are no longer used.

3) Create a single record from the unit
As noted in the code, You must create a table-valued function string parser.
This is pretty straight forward.  There are two kinds of records in a unit: Types 1, 2, and 7 are parsed into individual named fields via a table-valued function.  Type 5 records look like attribute-value pairs already.
Simply PIVOT the type 5 records to get a single record per unit (Detail).
Parse, UNION, and then PIVOT the Type 1, 2, and 7 to get a single record per unit (Header).  I did this in two logical steps.
Join Header and Detail to yield a single row per unit.
0
 
LVL 17

Author Comment

by:MIKE
ID: 41783974
many thanks!!
0
 
LVL 17

Author Closing Comment

by:MIKE
ID: 41784007
many thanks!!
0

Featured Post

Enterprise Mobility and BYOD For Dummies

Like “For Dummies” books, you can read this in whatever order you choose and learn about mobility and BYOD; and how to put a competitive mobile infrastructure in place. Developed for SMBs and large enterprises alike, you will find helpful use cases, planning, and implementation.

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

How to leverage one TLS certificate to encrypt Microsoft SQL traffic and Remote Desktop Services, versus creating multiple tickets for the same server.
The Delta outage: 650 cancelled flights, more than 1200 delayed flights, thousands of frustrated customers, tens of millions of dollars in damages – plus untold reputational damage to one of the world’s most trusted airlines. All due to a catastroph…
This video shows, step by step, how to configure Oracle Heterogeneous Services via the Generic Gateway Agent in order to make a connection from an Oracle session and access a remote SQL Server database table.
Via a live example, show how to backup a database, simulate a failure backup the tail of the database transaction log and perform the restore.

910 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question

Need Help in Real-Time?

Connect with top rated Experts

25 Experts available now in Live!

Get 1:1 Help Now