1

I have following data

enter image description here

I want to Convert Column to Row

I have use following Query ::

Select Distinct [ApplicantID],

Split.a.value('.', 'VARCHAR(100)') AS Subjects, 

hoursperweek,[Days],[Time] 

From ( Select 

       Cast ('<M>' + REPLACE([Subjects], ',', '</M><M>') + '</M>' AS XML) 

     AS Subjects , ApplicantID, hoursperweek,[Days],[Time] 

     From  [dbo].[Progrm])

AS A CROSS APPLY Subjects.nodes ('/M') AS Split(a)

It give me following Result

enter image description here

but I want to seprate Subjects, Hoursperweek, days, time. How can I do that ?

ApplicantID  Subjects  HoursPerWeek   Days       Time
1             a          12           Sun      12:45:12
1             b          25           Mon      14:45:12
3
  • 1
    You're a victim of poor db design. CSV's should never ever be stored in db tables. One value/row is the SQL way! Commented Mar 2, 2016 at 15:00
  • What is Split.a.value? Commented Mar 2, 2016 at 15:05
  • Personally, I wouldn't use SQL to fix this. I'd write a script to read the table, parse each row, and insert the resulting rows into a normalized destination table. Simply put, SQL is not built for text parsing, and it's really not built for working with completely denormalized data. Commented Mar 2, 2016 at 15:22

1 Answer 1

3

Here is a function to split the Comma separated values into Rows

CREATE FUNCTION dbo.Splitstrings (@List      NVARCHAR(MAX),
                                  @Delimiter NVARCHAR(255))
RETURNS @split_tab TABLE (
  RN        INT IDENTITY(1, 1),
  SPLIT_VAL VARCHAR(100))
WITH SCHEMABINDING
AS
  BEGIN ;
      ;WITH E1(N)
           AS (SELECT 1 UNION ALL SELECT 1 UNION ALL SELECT 1 UNION ALL
               SELECT 1 UNION ALL SELECT 1 UNION ALL SELECT 1 UNION ALL
               SELECT 1 UNION ALL SELECT 1 UNION ALL SELECT 1 UNION ALL SELECT 1),
           E2(N) AS (SELECT 1 FROM E1 a,E1 b),
           E4(N) AS (SELECT 1 FROM E2 a, E2 b),
           E42(N) AS (SELECT 1 FROM E4 a, E2 b),
           cteTally(N)
           AS (SELECT 0
               UNION ALL
               SELECT TOP (Datalength(Isnull(@List, 1))) Row_number()OVER (
                                                             ORDER BY (SELECT NULL))
               FROM   E42),
           cteStart(N1)
           AS (SELECT t.N + 1
               FROM   cteTally t
               WHERE  ( Substring(@List, t.N, 1) = @Delimiter
                         OR t.N = 0 ))
      INSERT INTO @split_tab
      SELECT SPLIT_VAL= Substring(@LIST, S.N1, Isnull(NULLIF(Charindex(@DELIMITER, @LIST, S.N1), 0) - S.N1, 8000))
      FROM   CTESTART S;

      RETURN
  END 

Now the ugly code to split the data

;WITH data
     AS (SELECT 1                   ApplicantID,
                'a,b'               Subjects,
                '12,25'             HoursPerWeek,
                'sun,mon'           Days,
                '12:45:12,14:45:12' Time),
     sub
     AS (SELECT RN,
                ApplicantID,
                Subjects=SPLIT_VAL
         FROM   data
                CROSS apply Splitstrings (Subjects, ',')),
     HPW
     AS (SELECT RN,
                ApplicantID,
                HoursPerWeek=SPLIT_VAL
         FROM   data
                CROSS apply Splitstrings (HoursPerWeek, ',')),
     Days
     AS (SELECT RN,
                ApplicantID,
                Days=SPLIT_VAL
         FROM   data
                CROSS apply Splitstrings (Days, ',')),
     Time
     AS (SELECT RN,
                ApplicantID,
                Time=SPLIT_VAL
         FROM   data
                CROSS apply Splitstrings (Time, ','))
SELECT D.APPLICANTID,
       S.SUBJECTS,
       H.HOURSPERWEEK,
       DA.DAYS,
       T.TIME
FROM   DATA D
       FULL OUTER JOIN SUB S
                    ON D.APPLICANTID = S.APPLICANTID
       FULL OUTER JOIN HPW H
                    ON D.APPLICANTID = H.APPLICANTID
                       AND H.RN = S.RN
       FULL OUTER JOIN DAYS DA
                    ON D.APPLICANTID = DA.APPLICANTID
                       AND DA.RN = COALESCE(S.RN, H.RN)
       FULL OUTER JOIN TIME T
                    ON D.APPLICANTID = T.APPLICANTID
                       AND T.RN = COALESCE(S.RN, H.RN, DA.RN) 

Result:

╔═════════════╦══════════╦══════════════╦══════╦══════════╗
║ APPLICANTID ║ SUBJECTS ║ HOURSPERWEEK ║ DAYS ║   TIME   ║
╠═════════════╬══════════╬══════════════╬══════╬══════════╣
║           1 ║ a        ║           12 ║ sun  ║ 12:45:12 ║
║           1 ║ b        ║           25 ║ mon  ║ 14:45:12 ║
╚═════════════╩══════════╩══════════════╩══════╩══════════╝

This is the reason we should never store comma separated values into single column. When you want to parse the data things get difficult and we need to such ugly codes to parse the data

Sign up to request clarification or add additional context in comments.

3 Comments

Instead of value how can I take column from table ? In a Query
@arti in the first cte (ie) data. remove values and add select applicationid,subject,hourperweek,.. from yourtable
thank you MotoGP for your help. Its working perfectly fine.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.