A friend of mine came across an issue where they needed to take data from a table, that had a label and a value, and then pivot it out into a single row and they were unsure of how to accomplish the goal.  So I created this little example to show them what needed to be done. 
In the data they have a table of labeled attributes combined with a sort order.  The sort order is the priority of any individual attribute, and the attributes have labels, and for any foreign key has a value associated with that specific label.   
Key, AttributeName, Attribute Value, SortOrder
An example would be:
 
  | 
FKeyValue | 
SortOrder | 
ItemName | 
ItemValue | 
  | 
1 | 
2 | 
Item2 | 
2 | 
  | 
1 | 
3 | 
Item3 | 
3 | 
  | 
1 | 
4 | 
Item4 | 
4 | 
  | 
1 | 
5 | 
Item5 | 
5 | 
  | 
2 | 
1 | 
Item1 | 
1 | 
  | 
2 | 
2 | 
Item2 | 
2 | 
  | 
2 | 
3 | 
Item3 | 
3 | 
  | 
2 | 
14 | 
Item14 | 
14 | 
  | 
2 | 
31 | 
Item31 | 
31 | 
  | 
2 | 
51 | 
Item51 | 
51 | 
And they want the data to pivot to:
 
  | 
fkeyvalue | 
att1name | 
att1value | 
att2name | 
att2value | 
att3name | 
att3value | 
att4name | 
att4value | 
att5name | 
att5value | 
  | 
1 | 
Item2 | 
2 | 
Item3 | 
3 | 
Item4 | 
4 | 
Item5 | 
5 | 
NULL | 
NULL | 
  | 
2 | 
Item1 | 
1 | 
Item2 | 
2 | 
Item3 | 
3 | 
Item14 | 
14 | 
Item31 | 
31 | 
So how do you approach this problem?  Because SQL doesn't allow you to pivot multiple item data, you have to approach the problem in parts.  My solution is to pivot the data twice around the foreign key, and use a row number assigned at the beginning of the operations to manage the column names and column order the data is exported. 
The idea is that you first create a table that has the order you want the data to be in, this gives you the attribute number, and aligns the data in the way you want it to appear in the columns.  The data after this initial sort step will look like:
 
  | 
FKeyValue | 
SortOrder | 
ItemName | 
ItemValue | 
row_num | 
  | 
1 | 
2 | 
Item2 | 
2 | 
1 | 
  | 
1 | 
3 | 
Item3 | 
3 | 
2 | 
  | 
1 | 
4 | 
Item4 | 
4 | 
3 | 
  | 
1 | 
5 | 
Item5 | 
5 | 
4 | 
  | 
2 | 
1 | 
Item1 | 
1 | 
1 | 
  | 
2 | 
2 | 
Item2 | 
2 | 
2 | 
  | 
2 | 
3 | 
Item3 | 
3 | 
3 | 
  | 
2 | 
14 | 
Item14 | 
14 | 
4 | 
  | 
2 | 
31 | 
Item31 | 
31 | 
5 | 
  | 
2 | 
51 | 
Item51 | 
51 | 
6 | 
Then you do two pivots, one pivot is to generate the name attribute columns, and the second pivot is to create the value attribute columns.  Then you join the columns back to their foreign key, and select the order you want the columns to be in. 
So the first pivoted table data would look like:
 
  | 
FKeyValue | 
1 | 
2 | 
3 | 
4 | 
5 | 
  | 
1 | 
Item2 | 
Item3 | 
Item4 | 
Item5 | 
NULL | 
  | 
2 | 
Item1 | 
Item2 | 
Item3 | 
Item14 | 
Item31 | 
 And the second pivoted table will look like:
 
  | 
FKeyValue | 
1 | 
2 | 
3 | 
4 | 
5 | 
  | 
1 | 
2 | 
3 | 
4 | 
5 | 
NULL | 
  | 
2 | 
1 | 
2 | 
3 | 
14 | 
31 | 
And after you join both tables together, and do a bit of column renaming you get:
| 
fkeyvalue | 
att1name | 
att1value | 
att2name | 
att2value | 
att3name | 
att3value | 
att4name | 
att4value | 
att5name | 
att5value | 
| 
1 | 
Item2 | 
2 | 
Item3 | 
3 | 
Item4 | 
4 | 
Item5 | 
5 | 
NULL | 
NULL | 
| 
2 | 
Item1 | 
1 | 
Item2 | 
2 | 
Item3 | 
3 | 
Item14 | 
14 | 
Item31 | 
31 | 
Below is a complete example, one done with temp tables, and one done with a CTE that also has a little bit of column renaming so you can see how to pull out appropriate column names dynamically using the row number from the data.
IF Object_id('tempdb..#tmp_multipivotexample') IS NOT NULL 
  BEGIN 
      DROP TABLE #tmp_multipivotexample 
  END 
/* First create some test data*/ 
CREATE TABLE #tmp_multipivotexample 
  ( 
     fkeyvalue INT
NOT NULL, 
     sortorder INT, 
     itemname 
VARCHAR(255), 
     itemvalue VARCHAR(255) 
  ) 
INSERT INTO #tmp_multipivotexample 
            (fkeyvalue, 
             sortorder,
             itemname,
             itemvalue)
SELECT 1       AS
KeyValue, 
       2      
AS SortOrder,
       'Item2' AS ItemName, 
       '2'     AS
ItemValue 
UNION 
SELECT 1       AS
FKeyValue, 
       4      
AS SortOrder,
       'Item4' AS ItemName, 
       '4'     AS ItemValue
UNION 
SELECT 1       AS
FKeyValue, 
       5      
AS SortOrder,
       'Item5' AS ItemName, 
       '5'     AS
ItemValue 
UNION 
SELECT 1       AS
FKeyValue, 
       3      
AS SortOrder,
       'Item3' AS ItemName, 
       '3'     AS
ItemValue 
UNION 
SELECT 2       AS
FKeyValue, 
       1      
AS SortOrder,
       'Item1' AS ItemName, 
       '1'     AS
ItemValue 
UNION 
SELECT 2       AS
KeyValue, 
       3      
AS SortOrder,
       'Item3' AS ItemName, 
       '3'     AS
ItemValue 
UNION 
SELECT 2        AS
FKeyValue, 
       14      
AS SortOrder,
       'Item14' AS ItemName, 
       '14'     AS
ItemValue 
UNION 
SELECT 2        AS
FKeyValue, 
       51      
AS SortOrder,
       'Item51' AS ItemName, 
       '51'     AS
ItemValue 
UNION 
SELECT 2        AS
FKeyValue, 
       31      
AS SortOrder,
       'Item31' AS ItemName, 
       '31'     AS
ItemValue 
UNION 
SELECT 2       AS
FKeyValue, 
       2      
AS SortOrder,
       'Item2' AS ItemName, 
       '2'     AS
ItemValue 
--select * from #tmp_multipivotexample
/* Second Now that we have data, lets grab the data and make faux row
numbers for the data for each key */
IF Object_id('tempdb..#InitialSortStep')
IS NOT NULL 
  BEGIN 
      DROP TABLE #initialsortstep 
  END 
SELECT *, 
       Row_number() 
         OVER( 
           partition
BY fkeyvalue 
           ORDER
BY sortorder ASC) row_num 
INTO   #initialsortstep 
FROM   #tmp_multipivotexample 
--select * from #InitialSortStep 
/* Now that we have the initial sort step, we can see it sorts the data
and properly assigned attribute numbers
so lets do the first pivot */ 
IF Object_id('tempdb..#PivotedItemNameByFKeyValue') IS NOT NULL 
  BEGIN 
      DROP TABLE #pivoteditemnamebyfkeyvalue 
  END 
SELECT * 
INTO   #pivoteditemnamebyfkeyvalue 
FROM   (SELECT fkeyvalue, 
               itemname,
               row_num 
        FROM   #initialsortstep)
AS InitPivot 
       PIVOT ( Max(itemname) 
             FOR
row_num IN ([1], 
                             [2], 
                             [3], 
                             [4], 
                             [5]) ) AS pivoted 
--select * from #pivoteditemnamebyfkeyvalue 
/*  Now to produce the properly
sorted item value data */
IF Object_id('tempdb..#PivotedItemValuesByFKeyValue') IS NOT NULL 
  BEGIN 
      DROP TABLE #pivoteditemvaluesbyfkeyvalue 
  END 
SELECT * 
INTO   #pivoteditemvaluesbyfkeyvalue 
FROM   (SELECT fkeyvalue, 
               itemvalue, 
               row_num 
        FROM   #initialsortstep)
AS InitPivot 
       PIVOT ( Max(itemvalue) 
             FOR
row_num IN ([1], 
                             [2], 
                             [3], 
                             [4], 
                             [5])
) AS pivoted 
--select * from #pivoteditemvaluesbyfkeyvalue
/* now to bring all of it together */
SELECT PINBFV.fkeyvalue, 
       PINBFV.[1]
AS att1name, 
       PINBFN.[1]
AS att1value, 
       PINBFV.[2]
AS att2name, 
       PINBFN.[2]
AS att2value, 
       PINBFV.[3]
AS att3name, 
       PINBFN.[3]
AS att3value, 
       PINBFV.[4]
AS att4name, 
       PINBFN.[4]
AS att4value, 
       PINBFV.[5]
AS att5name, 
       PINBFN.[5]
AS att5value 
FROM   #pivoteditemnamebyfkeyvalue PINBFV 
       JOIN
#pivoteditemvaluesbyfkeyvalue PINBFN 
         ON
PINBFV.fkeyvalue =
PINBFN.fkeyvalue 
/*now as a CTE, in this CTE I actually use the row number function to do
column naming as well, and re-designed the pivot
I think this makes it more readable. */ 
; 
WITH
cte_initialsortstep 
     AS (SELECT *, 
                Row_number() 
                  OVER( 
                    partition
BY fkeyvalue 
                    ORDER
BY sortorder ASC) row_num 
         FROM   #tmp_multipivotexample), 
     cte_pivoteditemnamebyfkeyvalue 
     AS (SELECT * 
         FROM   (SELECT fkeyvalue, 
                        itemname, 
                        'att' + Cast(row_num AS VARCHAR(10)) + 'name' AS Name 
                 FROM   cte_initialsortstep)
AS InitPivot 
                PIVOT ( Max(itemname) 
                      FOR
name IN ([att1name], 
                                   [att2name], 
                                   [att3name], 
                                   [att4name], 
                                   [att5name]) ) AS pivoted), 
     pivoteditemvaluesbyfkeyvalue 
     AS (SELECT * 
         FROM   (SELECT fkeyvalue, 
                        itemvalue, 
                        'att' + Cast(row_num AS VARCHAR(10)) 
                        + 'value' AS
Value 
                 FROM   #initialsortstep)
AS InitPivot 
                PIVOT ( Max(itemvalue) 
                      FOR
value IN ([att1value], 
                                    [att2value], 
                                    [att3value], 
                                    [att4value], 
                                    [att5value]) ) AS pivoted) 
SELECT PINBFV.fkeyvalue, 
       PINBFV.att1name  AS att1name, 
       PINBFN.att1value
AS att1value, 
       PINBFV.att2name  AS att2name, 
       PINBFN.att2value
AS att2value, 
       PINBFV.att3name  AS att3name, 
       PINBFN.att3value
AS att3value, 
       PINBFV.att4name  AS att4name, 
       PINBFN.att4value
AS att4value, 
       PINBFV.att5name  AS att5name, 
       PINBFN.att5value
AS att5value 
FROM   cte_pivoteditemnamebyfkeyvalue PINBFV 
       JOIN
pivoteditemvaluesbyfkeyvalue PINBFN 
         ON PINBFV.fkeyvalue = PINBFN.fkeyvalue