Example Schema:

    CREATE TABLE [dbo].[Base](
    [ID] [int] IDENTITY(1,1) NOT NULL,
    [Option1ID] [int] NULL,
    [Option2ID] [int] NULL,
    [Option3ID] [int] NULL,
    [Option1Name] [varchar] NULL,
    [Option2Name] [varchar] NULL,
    [Option3Name] [varchar] NULL,
    [Option1LName] [varchar] NULL,
    [Option2LName] [varchar] NULL,
    [Option3LName] [varchar] NULL,)

Is there a way to get results that show up like:

    ID | OptionID | OptionName | OptionLName

I have tried to achieve this using UNION ALL but this means going over the same row 3 times in my example, in my real problem I have to do it 10 times. I cannot normalize the table due to legacy code. Is there a way to only go over the Base row once?
Top Answer
Martin Smith (imported from SE)
You can use `CROSS APPLY ... VALUES` to `UNPIVOT` multiple columns

    SELECT ID,
           OptionID,
           OptionName,
           OptionLName
    FROM   [dbo].[Base]
           CROSS APPLY (VALUES([Option1ID], [Option1Name], [Option1LName]),
                              ([Option2ID], [Option2Name], [Option2LName]),
                              ([Option3ID], [Option3Name], [Option3LName])) 
                         V( OptionID, OptionName, OptionLName) 

The execution plan for this has one scan of `Base`. The plan is in fact the same as for the 2005 compatible rewrite that uses `UNION ALL`


    SELECT ID,
           OptionID,
           OptionName,
           OptionLName
    FROM   [dbo].[Base]
           CROSS APPLY (SELECT [Option1ID], [Option1Name], [Option1LName] UNION ALL
                        SELECT [Option2ID], [Option2Name], [Option2LName] UNION ALL
                        SELECT [Option3ID], [Option3Name], [Option3LName]) 
                         V( OptionID, OptionName, OptionLName)  

But I presume the `UNION ALL` you were trying to avoid was the multiple scans of 


    SELECT ID,
           [Option1ID],
           [Option1Name],
           [Option1LName]
    FROM   [dbo].[Base]
    UNION ALL
    SELECT ID,
           [Option2ID],
           [Option2Name],
           [Option2LName]
    FROM   [dbo].[Base]
    UNION ALL
    SELECT ID,
           [Option3ID],
           [Option3Name],
           [Option3LName]
    FROM   [dbo].[Base] 

This room is for discussion about this question.

Once logged in you can direct comments to any contributor here.

Enter question or answer id or url (and optionally further answer ids/urls from the same question) from

Separate each id/url with a space. No need to list your own answers; they will be imported automatically.