Avatar of soozh
soozh
Flag for Sweden asked on

SQL server converting rows to columns

I am sure this is a really simple question but my brain is not working today.

I have a table called persons that is defined as:
      [Id] [int] IDENTITY(1,1) NOT NULL,
      [PersonId] int not null,


      [IsBaseline] bit not null,


      [H_BAS_Visus] int,
      [V_BAS_Visus] int,


      [H_FU_Visus] int,
      [V_FU_Visus] int

Open in new window

The PersonId column uniquely defines the person.  The IsBaseline column defines whether the data has been collected at a baseline visit (it then has a value of true), or a follow up visit (value null/false).

When it is a baseline visit the columns *_BAS_Visus contain data, and when a follow up visit then the columns *_FU_Visus contain data.

I need to produce a view over this table where the columns are just PersonId, IsBaseline, and Visus.

So for every row in the Persons table there will be two rows in my view... one for each eye.

So this data:                                                
PersonIdIsBaselineH_BAS_VisusV_BasVisusH_FU_VisusV_FU_Visus
1112

10

34
20

56
30

78
41910


Should produce this:
 
PersonIdIsBaselineVisus
111
112
103
104
205
206
307
308
419
4110


Can anyone give me a few tips?



SQLMicrosoft SQL Server

Avatar of undefined
Last Comment
PortletPaul

8/22/2022 - Mon
Bembi

The keyword is transposing.
But your example is not just transposing, you want to aggregate individual colums into one single colum.
The question is now if this is a single task to change the table structure or a recuring task, you need a query for. 
ASKER CERTIFIED SOLUTION
Ryan Chong

THIS SOLUTION ONLY AVAILABLE TO MEMBERS.
View this solution by signing up for a free trial.
Members can start a 7-Day free trial and enjoy unlimited access to the platform.
See Pricing Options
Start Free Trial
GET A PERSONALIZED SOLUTION
Ask your own question & get feedback from real experts
Find out why thousands trust the EE community with their toughest problems.
soozh

ASKER
Thanks Ryan... As always the solution is pretty straight forward.
Andrei Fomitchev

I think that UNION ALL should be used in Ryan's suggestion. Otherwise UNION will exclude duplicates. For example, if value<1> == value<2> == 'Y' with UNION instead of two rows you will have only one. Conditions in Ryan suggestion should be corrected as well (4 times the same column name repeated in WHERE condition).

Another note, I think that the column visus_type should be added. Otherwise how do you know is visus H_FU_Visus or V_FU_Visus?

UNION with empty string will cause warnings.

It is better to do it in the following way - no warnings here:

    DECLARE @t TABLE (Id INT IDENTITY, PersonId Int, IsBaseline Int, Visus Int, VisusType Int)

    INSRT INTO @t (PersonId, IsBaseLine, Visus, VisusType)
    SELECT PersonId, IsBaseLine, H_BAS_Visus, 1 WHERE H_BAS_Visus IS NOT NULL;

    INSRT INTO @t (PersonId, IsBaseLine, Visus, VisusType)
    SELECT PersonId, IsBaseLine, V_BAS_Visus, 2 WHERE V_BAS_Visus IS NOT NULL;

    INSRT INTO @t (PersonId, IsBaseLine, Visus, VisusType)
    SELECT PersonId, IsBaseLine, H_FU_Visus, 3 WHERE H_FU_Visus IS NOT NULL;

    INSRT INTO @t (PersonId, IsBaseLine, Visus, VisusType)
    SELECT PersonId, IsBaseLine, V_FU_Visus, 4 WHERE V_FU_Visus IS NOT NULL;

    SElECT * FROM @t ORDER BY PersonId, VisusType;

Experts Exchange has (a) saved my job multiple times, (b) saved me hours, days, and even weeks of work, and often (c) makes me look like a superhero! This place is MAGIC!
Walt Forbes
PortletPaul

Set Operators - UNION


Concatenates the results of two queries into a single result set. You control whether the result set includes duplicate rows:

When transforming columns to rows you DO NOT want to loose data in the process,
hence you do not want/need to use UNION which can exclude some rows.

You should use UNION ALL which will not remove any data from the result.