Pivot Result Creation from SQL query using two tables and join - sql

I have my first table like this, it contains platform and their platform code
+-----------+------+
| platforms | code |
+-----------+------+
| java | 1 |
| .net | 2 |
| perl | 3 |
+-----------+------+
My second table contains columns as shown below.
+-------+------+------+------+
| pname | code | year | deve |
+-------+------+------+------+
| a | 1 | 2018 | abia |
| b | 1 | 2017 | arun |
| c | 2 | 2018 | abia |
| d | 3 | 2017 | arun |
| e | 2 | 2017 | arun |
| f | 3 | 2018 | abia |
+-------+------+------+------+
Result expected in Pivot Format like this:
+-----+-------+------+------+------+
| year| deve | .net | java | perl |
+-----+-------+------+------+------+
| 2018| abia | 1 | 1 | 1 |
| 2017| arun | 1 | 1 | 1 |
+-----+-------+------+------+------+

Try this Pivot Script which meets your expectation
DECLARE #Table AS TABLE
(platforms VARCHAR(20), code INT)
INSERT INTO #Table
SELECT 'java', 1 UNION ALL
SELECT '.net', 2 UNION ALL
SELECT 'perl', 3
DECLARE #Table2 AS TABLE
(pname VARCHAR(20), code INT,[year] INT, deve VARCHAR(20))
INSERT INTO #Table2
SELECT 'a',1,2018,'abia' UNION ALL
SELECT 'b',1,2017,'arun' UNION ALL
SELECT 'c',2,2018,'abia' UNION ALL
SELECT 'd',3,2017,'arun' UNION ALL
SELECT 'e',2,2017,'arun' UNION ALL
SELECT 'f',3,2018,'abia'
SELECT [year],deve,MAX([java]) AS [java],MAX([.net]) AS [.net],MAX([perl] ) AS [perl]
FROM
(
SELECT platforms,CASE WHEN pname IS NOT NULL THEN 1 ELSE NUll END AS pname ,A.code ,deve,[year] FROM #Table2 A
INNER JOIN #Table B
ON A.code=b.code
)
AS SRC
PIVOT
(
MAX(pname) FOR platforms IN( [java],[.net],[perl] )
) AS PVT
GROUP BY [year],deve
Result
year deve java .net perl
------------------------------------
2018 abia 1 1 1
2017 arun 1 1 1

Pivot using dynamic sql approach as it fits when the columns to be added dynamically to get the specific result
CREATE TABLE #Table
(platforms VARCHAR(20), code INT)
INSERT INTO #Table
SELECT 'java', 1 UNION ALL
SELECT '.net', 2 UNION ALL
SELECT 'perl', 3
CREATE TABLE #Table2
(pname VARCHAR(20), code INT,[year] INT, deve VARCHAR(20))
INSERT INTO #Table2
SELECT 'a',1,2018,'abia' UNION ALL
SELECT 'b',1,2017,'arun' UNION ALL
SELECT 'c',2,2018,'abia' UNION ALL
SELECT 'd',3,2017,'arun' UNION ALL
SELECT 'e',2,2017,'arun' UNION ALL
SELECT 'f',3,2018,'abia'
DECLARE #Columns nvarchar(max),
#IsnullColumns nvarchar(max),
#Sql nvarchar(max)
SELECT #Columns= STUFF((SELECT ', '+QUOTENAME(platforms) FROM #Table FOR XML PATH ('')),1,1,'')
SELECT #IsnullColumns=STUFF((SELECT ', '+'MAX('+QUOTENAME(platforms)+') AS ' +QUOTENAME(platforms) FROM #Table FOR XML PATH ('')),1,1,'')
SET #Sql='
SELECT[year],deve, '+#IsnullColumns+'
FROM
( SELECT platforms,
CASE WHEN pname IS NOT NULL THEN 1 ELSE NUll END AS pname ,A.code ,deve,[year]
FROM #Table2 A
INNER JOIN #Table B
ON A.code=b.code
) AS SRC
PIVOT
(MAX(pname) FOR platforms IN('+#Columns+')
) AS PVT
GROUP BY [year],deve'
PRINT #Sql
EXEC (#Sql)
Result
year deve java .net perl
------------------------------------
2018 abia 1 1 1
2017 arun 1 1 1

Related

SQL Server group pivot table according to id

I have a table called 'info':
|InfoId | OtherId | Year | InfoNo |
-------------------------------------
|1 | 1 | 2012 | abc |
|2 | 1 | 2013 | def |
|3 | 1 | 2014 | ghi |
I want to get this result:
| OtherId | 2012 | 2013 | 2014 |
---------------------------------
| 1 | abc | def | ghi |
i tried using:
SELECT *
FROM info
PIVOT (MAX(InfoNo)
FOR Year in ([2012],[2013],[2014])) AS pvt
where OtherId= '1'
But instead, I get this result:
| OtherId | 2012 | 2013 | 2014 |
---------------------------------
| 1 | abc | | |
| 1 | | def | |
| 1 | | | ghi |
How do I make the three rows group as one row according to 'OtherId'?
EDIT
I updated my SQL to the following and manage to get the result I wanted as well:
SELECT
OtherId,
MAX(case WHEN Year = '2012' THEN InvoiceNo ELSE NULL end) AS [2012],
MAX(case WHEN Year = '2013' THEN InvoiceNo ELSE NULL end) AS [2013],
MAX(case WHEN Year = '2014' THEN InvoiceNo ELSE NULL end) AS [2014]
FROM info
Thanks all for helping me.
You need to group your result by OtherId, I did a quick test and here's the result:
Select * FROM info
InfoId OtherId Year InfoNo
----------- ----------- ----------- ----------
1 1 2012 abc
2 1 2013 edf
3 1 2014 ghk
SELECT
pvt.OtherId,
MAX([2012]) AS '2012',
MAX([2013]) AS '2013',
MAX([2014]) AS '2014'
FROM info AS src
PIVOT (
MAX(InfoNo)
FOR [Year] IN ([2012],[2013],[2014]))
AS pvt
GROUP BY pvt.OtherId
Result:
OtherId 2012 2013 2014
----------- ---------- ---------- ----------
1 abc edf ghk
Hope that helps your cause.
IF OBJECT_ID('Tempdb..#Temp') IS NOt NUll
Drop Table #Temp
;With cte(InfoId ,OtherId ,[Year],InfoNo)
AS
(
SELECT 1,1,'2012' , 'abc' Union all
SELECT 2,1,'2013' , 'def' Union all
SELECT 3,1,'2014' , 'ghi'
)
SELECT * INTO #Temp FROM cte
DECLARE #dynamicCol nvarchar(max),#dynamicCol2 nvarchar(max),
#Sql nvarchar(max)
SELECT #dynamicCol=STUFF((SELECT DISTINCT ', ' + QUOTENAME(Year) FROM #Temp
FOR XML PATH('')),1,1,'')
SELECT #dynamicCol2=STUFF((SELECT DISTINCT ', ' + 'MAX('+ QUOTENAME(Year) +' )' +' AS '+ QUOTENAME(Year) FROM #Temp
FOR XML PATH('')),1,1,'')
SET #Sql= N' SELECT [OtherId] , '+ #dynamicCol2 +' From
(
SELECT InfoId ,OtherId ,[Year],InfoNo From
#temp
)AS Src
PIVOT
(
MAX([InfoNo]) For [Year] IN ('+#dynamicCol+')
)
AS Pvt
GROUP BY Pvt.OtherId
'
PRINT #Sql
EXEC(#Sql)
OutPut
| OtherId | 2012 | 2013 | 2014 |
---------------------------------
| 1 | abc | def | ghi |

Recursive CTE (T-SQL) Returns Un-expected Result

I've been staring at this code for WAY too long, trying to figure out why my final query returns unexpected results.
Any help would be much appreciated. Thanks in advance.
Given the following code (running on SQL Server 2008 R2):
USE tempdb;
DECLARE #emp--loyee
TABLE (
EmployeeID int NOT NULL
,EmployeeName nvarchar(50) NOT NULL
PRIMARY KEY(EmployeeID)
)
INSERT INTO #emp
SELECT 1,'Fred'
UNION
SELECT 2,'Mary'
UNION
SELECT 3,'Joe'
UNION
SELECT 4,'Bill'
DECLARE #grp TABLE (
GroupID int NOT NULL
,GroupName nvarchar(50)
PRIMARY KEY(GroupID)
)
INSERT INTO #grp
SELECT 1,'Group 1'
UNION
SELECT 2,'Group 2'
UNION
SELECT 3,'Group 3'
DECLARE #empgrp TABLE (
EmployeeID int NOT NULL
,GroupID int NOT NULL
PRIMARY KEY (EmployeeID,GroupID)
)
INSERT INTO #empgrp
SELECT 1,1
UNION
SELECT 2,1
UNION
SELECT 3,1
UNION
SELECT 4,2
DECLARE #grpgrp TABLE (
GroupID int NOT NULL
,ParentGroupID int
,UNIQUE CLUSTERED(GroupID,ParentGroupID)
)
INSERT INTO #grpgrp
SELECT 1,2
UNION
SELECT 2,3;
WITH AllEmpGroups (EmployeeID,GroupID,RootGroupID)
AS
(
SELECT CAST(NULL as int) as EmployeeID,pgrp.GroupID,pgrp.ParentGroupID
FROM #grpgrp pgrp LEFT JOIN #grpgrp ggrp
ON pgrp.ParentGroupID = ggrp.GroupID
UNION ALL
SELECT e.EmployeeID,eg.GroupID,aeg.RootGroupID
FROM #emp e JOIN #empgrp eg
ON e.EmployeeID = eg.EmployeeID
JOIN #grpgrp ggrp
ON eg.GroupID = ggrp.GroupID
JOIN AllEmpGroups aeg
ON aeg.GroupID = ggrp.ParentGroupID
)
SELECT EmployeeID,GroupID,RootGroupID
FROM AllEmpGroups
What I get is:
+------------+---------+-------------+
| EmployeeID | GroupID | RootGroupID |
+------------+---------+-------------+
| NULL | 1 | 2 |
| NULL | 2 | 3 |
| 1 | 1 | 3 |
| 2 | 1 | 3 |
| 3 | 1 | 3 |
+------------+---------+-------------+
What I would expect/want to get is this:
+------------+---------+-------------+
| EmployeeID | GroupID | RootGroupID |
+------------+---------+-------------+
| NULL | 1 | 2 |
| NULL | 2 | 3 |
| 4 | 2 | 3 |
| 1 | 1 | 3 |
| 2 | 1 | 3 |
| 3 | 1 | 3 |
+------------+---------+-------------+
Bottom line, I want the full recursive stack of all employees beneath a given root group(s), with the root group id on every row.
What am I missing?
First:
You need a row for the root node in #grpgrp with values 3, null
The anchor (part before the union all) of your recursive cte needs to be the root node (3, null) for ancestor first recursion.
...
INSERT INTO #grpgrp
SELECT 1,2
UNION all
SELECT 2,3
UNION all
select 3, null;
WITH AllEmpGroups (EmployeeID,GroupID,RootGroupID)
AS
(
SELECT CAST(NULL as int) as EmployeeID,pgrp.GroupID, ParentGroupID = pgrp.GroupID
FROM #grpgrp pgrp LEFT JOIN #grpgrp ggrp
ON pgrp.ParentGroupID = ggrp.GroupID
where pgrp.ParentGroupId is null
UNION ALL
SELECT e.EmployeeID,eg.GroupID,aeg.RootGroupID
FROM #emp e JOIN #empgrp eg
ON e.EmployeeID = eg.EmployeeID
JOIN #grpgrp ggrp
ON eg.GroupID = ggrp.GroupID
JOIN AllEmpGroups aeg
ON aeg.GroupID = ggrp.ParentGroupID
)
SELECT EmployeeID,GroupID,RootGroupID
FROM AllEmpGroups
rextester demo: http://rextester.com/CBWY80387
returns:
+------------+---------+-------------+
| EmployeeID | GroupID | RootGroupID |
+------------+---------+-------------+
| NULL | 3 | 3 |
| 4 | 2 | 3 |
| 1 | 1 | 3 |
| 2 | 1 | 3 |
| 3 | 1 | 3 |
+------------+---------+-------------+
Beyond that, I would build the groups hierarchy first, then join the employees like so:
WITH AllEmpGroups (GroupID,ParentGroupID,RootGroupID)
AS
(
SELECT pgrp.GroupID, pgrp.ParentGroupID, RootGroupId = GroupID
FROM #grpgrp pgrp
where pgrp.ParentGroupId is null
UNION ALL
SELECT ggrp.GroupID,ggrp.ParentGroupID,aeg.RootGroupID
FROM #grpgrp ggrp
inner JOIN AllEmpGroups aeg
ON aeg.GroupID = ggrp.ParentGroupID
)
SELECT eg.EmployeeID,aeg.*
FROM AllEmpGroups aeg
left JOIN #empgrp eg
ON eg.GroupID = aeg.GroupID
rextester demo: http://rextester.com/FAK76354
returns:
+------------+---------+---------------+-------------+
| EmployeeID | GroupID | ParentGroupID | RootGroupID |
+------------+---------+---------------+-------------+
| NULL | 3 | NULL | 3 |
| 4 | 2 | 3 | 3 |
| 1 | 1 | 2 | 3 |
| 2 | 1 | 2 | 3 |
| 3 | 1 | 2 | 3 |
+------------+---------+---------------+-------------+
Start with
WITH AllGroups (RootGroupID,GroupID,ParentGroupID, level)
AS
(
SELECT GroupID RootGroupID, GroupID, Cast(NULL as int) ParentGroupID, 0 level
FROM #grp g
WHERE NOT EXISTS (SELECT 1 FROM #grpgrp gg WHERE gg.GroupID = g.GroupID)
UNION ALL
SELECT ag.RootGroupID, gg.GroupID, gg.ParentGroupID, level+1
FROM #grpgrp gg
JOIN AllGroups ag
ON ag.GroupID = gg.ParentGroupID
)
SELECT EmployeeID, ag.GroupID, ParentGroupID, RootGroupID
FROM AllGroups ag
LEFT JOIN #empgrp eg ON eg.GroupID = ag.GroupID
ORDER BY RootGroupID, level, ParentGroupID, GroupID;
Not sure why you need the row:
| NULL | 2 | 3 |

Join Vertical & Horizontal table in SQL Server using Pivot

I want to join two tables and combine into one but problem is one table is in Horizontal Format and other in Vertical format.
below is the table structure and join will be on Employeeid:
Table 1 : EmpDetail
ID | CODE | Name
-- |--------| ---
1 | 1008M | ABC
2 | 1039E | XYZ
3 | 1040E | TYS
Table 2 : EmpCustomeDetail
EmpID | FiledName | FieldValue
-- |-------- | ---
1 | FlD1 | temp1
1 | FlD2 | temp2
1 | FlD3 | temp3
2 | FlD1 | temp1
3 | FLD4 | temp6
Desired Output Required :
EmpID | Code | Name | Fld1 | Fld2 | Fld3 | Fld4
-- |---- | ------| --- | ---- |---- |----
1 | 1008M | ABC | temp1 | temp2 | temp3 | null
2 | 1039E | XYZ | temp1 | null | null | null
3 | 1040E | TYS | null | null | null | temp6
I had tried using Pivot Query but it is not giving exact output which i requried
Below is the query so far i have tried
SELECT A.*
FROM (
SELECT
e.Id,
e.code,
e.Fname,
FROM EmpDetail e
LEFT JOIN (
SELECT *
FROM (
SELECT
d.CustomeFieldName
, c.ComboValue
, d.EmployeeId
FROM EmpCustomeDetail d
) src
PIVOT (
MAX(FieldValue)
) src2
) c ON e.Id = c.EmployeeId
) A
Here are two statements:
The first is a simple PIVOT. You can use it, in case you know all Fieldnames (btw: there's a typo in your sample) in advance.
The second is roughly the same statement, but the column names are taken dynamically. This will work with (almost) any count and with different namings.
First a mock-up-test-scenraio
CREATE TABLE DummyEmpDetail (ID INT,CODE VARCHAR(10),Name VARCHAR(100));
INSERT INTO DummyEmpDetail VALUES
(1,'1008M','ABC')
,(2,'1039E','XYZ')
,(3,'1040E','TYS');
CREATE TABLE DummyEmpCustomeDetail (EmpID INT,FiledName VARCHAR(100),FieldValue VARCHAR(100));
INSERT INTO DummyEmpCustomeDetail VALUES
(1,'FlD1','temp1')
,(1,'FlD2','temp2')
,(1,'FlD3','temp3')
,(2,'FlD1','temp1')
,(3,'FLD4','temp6');
--The static PIVOT statement
SELECT p.EmpID
,p.Name
,p.CODE
,p.Fld1
,p.Fld2
,p.Fld3
p,Fld4
FROM
(
SELECT e.CODE,e.Name,ec.*
FROM DummyEmpDetail AS e
INNER JOIN DummyEmpCustomeDetail AS ec ON e.ID=ec.EmpID
) AS tbl
PIVOT
(
MAX(FieldValue) FOR FiledName IN(Fld1,Fld2,Fld3,Fld4)
) AS p;
--The dynamic PIVOT statement
DECLARE #colNames VARCHAR(MAX)=
(
STUFF
(
(
SELECT DISTINCT ',' + QUOTENAME(FiledName) FROM DummyEmpCustomeDetail
FOR XML PATH('')
),1,1,''
)
);
DECLARE #command VARCHAR(MAX)=
'SELECT p.EmpID
,p.Name
,p.CODE
,' + #colNames +
' FROM
(
SELECT e.CODE,e.Name,ec.*
FROM DummyEmpDetail AS e
INNER JOIN DummyEmpCustomeDetail AS ec ON e.ID=ec.EmpID
) AS tbl
PIVOT
(
MAX(FieldValue) FOR FiledName IN(' + #colnames + ')
) AS p;';
EXEC (#command);
GO
DROP TABLE DummyEmpCustomeDetail;
DROP TABLE DummyEmpDetail;
Both lead to the same result...
Try like below. If values of fieldname will not be static then you should use dynamic sql.
SELECT EMPID,
CODE,
NAME,
FLD1,
FLD2,
FLD3,
FLD4
FROM EmpDetail C
JOIN (SELECT A.*
FROM EmpCustomeDetail
PIVOT ( MIN([FIELDVALUE])
FOR [FILEDNAME] IN([FLD1],
[FLD3],
[FLD2],
FLD4) )A)B
ON C.ID = B.[EMPID]
No need for sub-queries.
select e.*,FlD1,FlD2,FlD3,FlD4
from EmpDetail e
left join EmpCustomeDetail
pivot (max(FieldValue) for FiledName in (FlD1,FlD2,FlD3,FlD4)) ecd
on ecd.EmpID = e.ID
+----+-------+------+-------+-------+-------+-------+
| ID | CODE | Name | FlD1 | FlD2 | FlD3 | FlD4 |
+----+-------+------+-------+-------+-------+-------+
| 1 | 1008M | ABC | temp1 | temp2 | temp3 | NULL |
+----+-------+------+-------+-------+-------+-------+
| 2 | 1039E | XYZ | temp1 | NULL | NULL | NULL |
+----+-------+------+-------+-------+-------+-------+
| 3 | 1040E | TYS | NULL | NULL | NULL | temp6 |
+----+-------+------+-------+-------+-------+-------+

Move multiple row values in a single row in SQL

I have below table
TABLE A
| S | D |
----------
| 1 | 01 |
| 2 | 01 |
| 2 | 03 |
I want my query result in the below format
| S | D |
|1,2| 01 |
| 2 | 03 |
How can I get this in SQL
with the help of STUFF we can achieve this
declare #temp table
(
S int,
D nvarchar(10)
)
insert into #temp values (1,'01')
insert into #temp values (2,'01')
insert into #temp values (2,'03');
SELECT D,
STUFF(
(SELECT ',' + CAST(S AS VARCHAR(10))
FROM #temp
WHERE D = a.D
FOR XML PATH (''))
, 1, 1, '') AS Remark
FROM #temp AS a
GROUP BY D

Create New Table From Other Table After Grouping

How can I insert to a table a value from "grouping" other table?
That means I have 2 table with different structure.
The table ORDRE with existed DATA
Table ORDRE:
ORDRE ID | CODE_DEST |
-------------------------
1 | a |
2 | b |
3 | c |
4 | a |
5 | a |
6 | b |
7 | g |
I want to INSERT the value FROM Table ORDRE INTO TABLE VOIT:
ID_VOIT | ORDRE ID | CODE_DEST |
---------------------------------------
1 | 1 | a |
1 | 4 | a |
1 | 5 | a |
2 | 2 | b |
2 | 6 | b |
3 | 3 | c |
4 | 7 | g |
This is my best guess on what you need using only the info available.
declare #Ordre table
(
ordre_id int,
code_dest char(1)
)
declare #Voit table
(
id_voit int,
ordre_id int,
code_dest char(1)
)
insert into #Ordre values
(1,'a'),
(2,'b'),
(3,'c'),
(4,'a'),
(5,'a'),
(6,'b'),
(7,'g')
insert into #Voit
select id_voit, ordre_id, rsOrdre.code_dest
from #Ordre rsOrdre
inner join
(
select code_dest, ROW_NUMBER() over (order by code_dest) as id_voit
from #Ordre
group by code_dest
) rsVoit on rsVoit.code_dest = rsOrdre.code_dest
order by id_voit, ordre_id
select * from #Voit
Working Example.
For the specific data you give as an example, this works:
insert into VOIT
select
case code_dest
when 'a' then 1
when 'b' then 2
when 'c' then 3
when 'g' then 4
else 0
end, orderId, code_dest from ORDRE order by code_dest, orderId
But it kind of sucks because it requires hard-coding in a huge case statement.
Test is here - https://data.stackexchange.com/stackoverflow/q/119442/
What I like more is moving the VOIT ID / Code_Dest associations to a new table, so then you could do an inner join instead.
insert into VOIT
select voit_id, orderId, t.code_dest
from ORDRE t
join Voit_CodeDest t2 on t.code_dest = t2.code_dest
order by code_dest, orderId
Working example of that here - https://data.stackexchange.com/stackoverflow/q/119443/