I have a Person table. Each person can have many names in the PersonNames table. I would like to get for each person, 2 of his first names and 2 of his last names in one row. like this:
PersonId | FName1 | Fname2  | Lname1    | Lname2
1          David    Daniekl   Bekernman   Stivens
Person table:
   PersonId
   BirthDate
PersonNames table:
   PersonId
   NameId
   Name
   NameType (e.g; first, last...)
Thanks.
In SQL Server you can use the PIVOT function to transform the data from rows to columns: select Firstname, Amount, PostalCode, LastName, AccountNumber from ( select value, columnname from yourtable ) d pivot ( max(value) for columnname in (Firstname, Amount, PostalCode, LastName, AccountNumber) ) piv; See Demo.
Display Row Values as Columns in MySQL Dynamically You can customize the above query as per your requirements by adding WHERE clause or JOINS. If you want to transpose only select row values as columns, you can add WHERE clause in your 1st select GROUP_CONCAT statement.
If this is specifically for just two names, this will pick up the names with the MIN and MAX NameId per Person...
SELECT
  Person.PersonId,
  MAX(CASE WHEN Name.nameId = map.minNameId AND Name.nameType = 'first' THEN Name.Name ELSE NULL END) AS fname1,
  MAX(CASE WHEN Name.nameId = map.minNameId AND Name.nameType = 'last'  THEN Name.Name ELSE NULL END) AS lname1,
  MAX(CASE WHEN Name.nameId = map.maxNameId AND Name.nameType = 'first' THEN Name.Name ELSE NULL END) AS fname2,
  MAX(CASE WHEN Name.nameId = map.maxNameId AND Name.nameType = 'last'  THEN Name.Name ELSE NULL END) AS lname2
FROM
  Person
LEFT JOIN
  (SELECT personId, MIN(nameId) AS minNameId, MAX(nameId) as maxNameId FROM PersonNames GROUP BY PersonId) AS map
    ON map.PersonId = Person.PersonId
LEFT JOIN
  PersonNames AS Name
    On Name.PersonId = Person.PersonId
GROUP BY
  Person.PersonId
EDIT
Now that I can see that this is MS SQL Server, there is another option. Similar to others here, but possibly slightly simpler...
WITH
  sequenced_names AS
(
  SELECT
    DENSE_RANK() OVER (PARTITION BY PersonId ORDER BY NameID) AS NameOrdinal,
    *
  FROM
    PersonNames
)
SELECT
  PersonID,
  MAX(CASE WHEN nameOrdinal = 1 AND nameType = 'first' THEN Name END) AS fname1,
  MAX(CASE WHEN nameOrdinal = 1 AND nameType = 'last'  THEN Name END) AS lname1,
  MAX(CASE WHEN nameOrdinal = 2 AND nameType = 'first' THEN Name END) AS fname2,
  MAX(CASE WHEN nameOrdinal = 2 AND nameType = 'last'  THEN Name END) AS lname2
FROM
  sequenced_names
GROUP BY
  PersonID
                        If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With