2

Person Table

enter image description here

Car Table

enter image description here

Select

enter image description here

How to get the above selection that shows the result in just two lines?

So far I've used INNER JOIN and GROUP BY, but I didn't get what I need.

John Simon
  • 149
  • 7
  • 2
    Why do you want to do this? SQL is row-oriented, not column-oriented. Pivoting rows-to-columns should be done only in the presentation-layer of your application, not in SQL. As soon as you PIVOT in SQL you lose the ability to meaningfully process the data any further in SQL. Also, having duplicate column names also breaks everything, – Dai Sep 25 '21 at 02:10
  • Understand. I will change my codes. Thanks – John Simon Sep 25 '21 at 02:35
  • @Dai SQL is set oriented language and there is nothing "incorrect" about pivoting rows to columns. The strength in SQL comes from processing the data in set oriented manner, which is much efficent than a row by row processing. The sad part about sql is that it is an underused, feature rich language. The processing layer can be used to decide how to show up the data on browser/app – George Joseph Sep 25 '21 at 02:46
  • @GeorgeJoseph I argue it is “incorrect” (your words) to PIVOT _in this context_ because it fundamentally breaks with Codd’s model (…not that I want to be seen defending Codd, though). – Dai Sep 25 '21 at 02:49
  • @JohnSimon Please check my answer and let me does it serve your purpose or not. Best Wishes. – Srijon Chakraborty Sep 25 '21 at 04:40

2 Answers2

1

I think I have a solution for you. To achieve your answer you need to use Pivot and dynamic column. Here is my solution given below.

DECLARE @DRCol varchar(500);
DECLARE @DRColWITHMax varchar(500);
DECLARE @Prefix varchar(20)='Car.Color';

DECLARE @temp TABLE(p_id int,columnName VARCHAR(10),rn int);
--PERSON Table
CREATE TABLE #tmpPerson(id int,pname VARCHAR(10));
INSERT INTO #tmpPerson VALUES
(1,'John'),
(2,'Sarah')
--Car Table
create table  #tmp(id int,p_id int,color VARCHAR(10));
INSERT INTO #tmp VALUES
 (1,1,'blue'),
(2,1,'Red'),
(3,1,'black'),
(4,2,'white');

--Using This table for dynamic Column Generation
INSERT INTO @temp
SELECT p_id,@Prefix + CAST(ROW_NUMBER() OVER(PARTITION BY p_id ORDER BY color) AS VARCHAR(MAX)) AS columnName,
        ROW_NUMBER()over(partition by p_id order by color)rn
FROM #tmp AS m;

--Dynamic Column Generation For Pivot
select top 1 
@DRCol=stuff((select ','+'['+@Prefix+cast(rn as varchar)+']' 
from @temp c1 where c.p_id=c1.p_id for xml path('')),1,1,'')
from @temp c
where c.p_id=(select top 1 p_id from @temp c1 order by rn desc);

--Dynamic Column Generation For Group By
SELECT top 1 
@DRColWITHMax=stuff((select ','+'MAX(['+@Prefix+cast(rn as varchar)+']) as ['+@Prefix+cast(rn as varchar)+']' 
FROM @temp c1 where c.p_id=c1.p_id for xml path('')),1,1,'')
FROM @temp c
WHERE c.p_id=(SELECT top 1 p_id from @temp c1 order by rn desc);

DECLARE @Sql varchar(2000)='';

 set @Sql='   
 WITH CTE AS
 (
    SELECT p.*
    FROM
    (
        SELECT *,pName=(Select TOP 1 pname FROM #tmpPerson as tp Where tp.id=m.p_id)
               ,'''+@Prefix+'''+ cast(ROW_NUMBER() OVER(PARTITION BY p_id ORDER BY id) as varchar(max))  columnName
        FROM #tmp AS m
    ) AS t PIVOT(MAX(color) FOR columnName IN('+@DRCol+')) AS p
 )
 Select p_id,pName, '+@DRColWITHMax+'
 FROM CTE GROUP BY p_id,pName
';
exec(@sql);
drop table #tmp;
drop table #tmpPerson;

Output:
enter image description here
Note: I made this query SQL Server 2016 and took help from this Answer.

Srijon Chakraborty
  • 2,007
  • 2
  • 7
  • 20
1

You can use conditional aggregation:

select p.id, p.name,
       max(case when seqnum = 1 then c.color end) as color_1,
       max(case when seqnum = 2 then c.color end) as color_2,
       max(case when seqnum = 3 then c.color end) as color_3
from (select c.*,
             row_number() over (partition by p_id order by id) as seqnum
      from car c
     ) c join
     person p
     on c.p_id = p.id
group by p.id, p.name;

Note that the above does not include the person id repeated through the row. That seems quite redundant.

Gordon Linoff
  • 1,242,037
  • 58
  • 646
  • 786