Can I pivot dynamic table with no group by in SQL Server - sql

This is my data in table (left join from field table and value table)
This is my expected result table after use pivot function
Thanks for help ^___^

I suggest you to use dynamic SQL as fieldnames number may very in future:
DECLARE #columns nvarchar(max),
#sql nvarchar(max)
SELECT #columns = COALESCE(#columns,'') + ',' + QUOTENAME(c.fieldname)
FROM [Columns] c
ORDER BY c.cid
SELECT #sql = N'
SELECT *
FROM (
SELECT v.[row],
c.fieldname,
v.fieldvalue
FROM [Values] v
INNER JOIN [Columns] c
ON v.cid = c.cid
) t
PIVOT (
MAX(fieldvalue) FOR fieldname IN ('+STUFF(#columns,1,1,'')+')
) pvt'
EXEC sp_executesql #sql
Will output:
row FirstName LastName Email Phone
1 Arnun Saelim Arnun.s#outlook.com 0922743838
2 Micheal Saelim Micheal#gmail.com 0886195353

I'm not sure why group by got into your mind, but here is a working example of what you are trying to achieve.
select * into #temp from
( values
(1,'A','AV'),
(1,'B','BV'),
(1,'C','CV'),
(2,'A','AV'),
(2,'B','BV'),
(2,'C','CV'))
as t(row, FieldName, FieldValue)
select *
from #temp
PIVOT
(MAX(FieldValue) FOR FieldName in ([A],[B],[C])) as pvt
Does that work for you?

Related

Pivot SQL with top 1

I have a simple table, with scan data in rows.
I want to pivot the dataset, with the first scan in each phase_key.
Into this:
I use this sql:
select
d.shipment_id,
d.carrier_reference,
e.phase_key,
e.event,
CONVERT(DATETIME,e.time) AS ScanDate
from
data d
inner join event e on d.id = e.data_id
where
shipment_id = '99156136'
order by e.time asc
I have tried using the suggested sql. (adding 1 id, to verify format. But it loads without the code suggested from #gotqn.
DECLARE #DynammicTSQLStatement NVARCHAR(MAX)
,#DynamicPIVOTColumns NVARCHAR(MAX);
SELECT #DynamicPIVOTColumns = STRING_AGG(CAST(QUOTENAME([phase_key]) AS VARCHAR(MAX)), ',') WITHIN GROUP (ORDER BY [phase_key])
FROM
(
SELECT DISTINCT [phase_key]
FROM data d
inner join event e on d.id = e.data_id
) DS ([phase_key]);
SET #DynammicTSQLStatement = N'
SELECT *
FROM
(
SELECT shipment_id
,phase_key
,time
FROM data d
inner join event e on d.id = e.data_id
where
shipment_id = "99156136"
) DS
PIVOT
(
MAX([time]) FOR [phase_key] IN (' + #DynamicPIVOTColumns + ')
) PVT';
EXEC sp_executesql #DynammicTSQLStatement;
But after 2mins it still have not loaded the 1. id om trying as a sample.
Try this:
DECLARE #DynammicTSQLStatement NVARCHAR(MAX)
,#DynamicPIVOTColumns NVARCHAR(MAX);
SELECT #DynamicPIVOTColumns = STRING_AGG(CAST(QUOTENAME([phase_key]) AS VARCHAR(MAX)), ',') WITHIN GROUP (ORDER BY [phase_key])
FROM
(
SELECT DISTINCT [phase_key]
FROM [my_table]
) DS ([phase_key]);
SET #DynammicTSQLStatement = N'
SELECT *
FROM
(
SELECT shipment_id
,phase_key
,ScanDate
FROM [my_table]
) DS
PIVOT
(
MAX([ScanDate]) FOR [phase_key] IN (' + #DynamicPIVOTColumns + ')
) PVT';
EXEC sp_executesql #DynammicTSQLStatement;

How to get columns with specific string

I am working in SQL Server 2014 and below is my database with which I am working on and need some analysis done on it.
Upon inspecting the database sample carefully we can notice a number 8777 in L9 and in L13 column.
Now I want to get only those columns which have 8777 in them and in the end a column named "count" which shows how many times the number appeared means I need in output something like this as shown below:
So far I have written this query which is giving the category and subcategory correct. But it is showing all the columns. I have no idea how to count the occurrences of a number and show its count in a count column.
select *
from Sheet2$
where '8777' IN ([L1],[L2],[L3],[L4],[L5],[L6],[L7],[L8],[L9],[L10],[L11],[L12],[L13]
To dynamically limit the columns, you would need Dynamic SQL
Example
Select *
Into #Temp
From YourTable A
Unpivot ( Value for Item in ([L1], [L2],[ L3], [L4], [L5], [L6], [L7], [L8], [L9], [L10], [L11], [L12], [L13]) ) u
Where Value = 8777
Declare #SQL varchar(max) = Stuff((Select Distinct ',' + QuoteName(Item) From #Temp Order by 1 For XML Path('')),1,1,'')
Select #SQL = '
Select *,[Count] = sum(1) over()
From #Temp A
Pivot (max(Value) For [Item] in (' + #SQL + ') ) p'
Exec(#SQL);
Returns
Category SubCategory L13 L9 Count
C1 SC1 NULL 8777 2
C1 SC3 8777 NULL 2
Hmmm. I think you want the original rows with the count. I think this is:
declare #cols nvarchar(max);
declare #sql nvarchar(max);
set #cols = (select distinct ', ' + v.colname
from t cross apply
(values ('l1', l1),
('l2', l2),
('l3', l3),
('l4', l4),
('l5', l5),
('l6', l6),
('l7', l7),
('l8', l8),
('l9', l9),
('l10', l10),
('l11', l11),
('l12', l12),
('l13', l13)
) v(colname, val)
where v.val = '8777'
for xml path ('')
);
set #sql = '
select category, subcategory' + #cols + ',
count(*) over () as cnt
from t
';
exec sp_executesql #sql;
The only difference from your result is that the count is on every row. That can easily be adjusted using a case expression, but I'm not sure it is necessary.
If you want the count in only one row, then:
set #sql = '
select category, subcategory' + #cols + ',
(case when row_number() over (order by category, subcategory) = 1
then count(*) over ()
end) as cnt
from t
order by category, subcategory
';
You can try this part as a replacement of John's answer's second query to get the proper count, it does not achieve the exact thing you want but can be a work around.
Declare #sql varchar(max) = Stuff((Select Distinct ',' + QuoteName(Item)
From #Temp Order by 1 For XML Path('')),1,1,'')
print #sql;
Select #SQL = '
Select *,value=8777
From #Temp A
Pivot (Count(Value) For [Item] in (' + #sql + ') ) p'
print #sql;
Exec(#SQL);
I just used count function in pivot in place of sum.

Show value of particular column as Header in SQL Server

I am creating a web app in which I have a requirement where I want to display a column value as a header
Example
SELECT Name, Leave
FROM tblUser
INNER JOIN tblLeaveMaster ON tblUser.EmployeeID = tblLeaveMaster.EmployeeID
From that query, I get these results:
Name Leave
---------------
Test1 5
Test2 10
test3 2
Now I want to get these values as
Test1 Test2 Test3
-----------------
5 10 2
How can I achieve this?
You can try using pivot
select pv.* from
(SELECT Name,Leave
FROM tblUser INNER JOIN tblLeaveMaster ON tblUser.EmployeeID=tblLeaveMaster.EmployeeID
)X
pivot
(max(leave) for name in ([Test1],[Test2],[Test3])) as pv
For Dynamic PIVOT
declare #sql varchar(max)='',#col_list varchar(8000)=''
set #col_list = (select distinct quotename([Name])+',' from (SELECT Name,Leave
FROM tblUser INNER JOIN tblLeaveMaster ON tblUser.EmployeeID=tblLeaveMaster.EmployeeID
)X
for xml path(''))
set #col_list = left (#col_list,len(#col_list)-1)
set #sql = 'select '+#col_list+' from
(SELECT Name,Leave
FROM tblUser INNER JOIN tblLeaveMaster ON tblUser.EmployeeID=tblLeaveMaster.EmployeeID
)X
pivot (max([Leave]) for [Name] in ('+#col_list+'))pv'
exec(#sql)
try by using case when
select max( case when name='Test1' then Leave end) as test1,
max( case when name='Test2' then Leave end) as test2,
max( case when name='Test3' then Leave end) as test3 from
tblUser INNER JOIN tblLeaveMaster
ON tblUser.EmployeeID=tblLeaveMaster.EmployeeID
You can try to use condition aggregate function. CASE WHEN with MAX or MIN
SELECT
MAX(CASE WHEN Name = 'Test1' THEN Leave END) Test1,
MAX(CASE WHEN Name = 'Test2' THEN Leave END) Test2,
MAX(CASE WHEN Name = 'Test3' THEN Leave END) Test3
FROM tblUser
INNER JOIN tblLeaveMaster ON tblUser.EmployeeID=tblLeaveMaster.EmployeeID
EDIT
If your column want to create dynamic you can try to use Dynamic PIVOT
create your SQL statement and make condition aggregate function by connect SQL string. then use execute it Dynamically.
DECLARE #cols AS NVARCHAR(MAX),
#query AS NVARCHAR(MAX);
SET #cols = STUFF((SELECT distinct ', MAX(CASE WHEN Name = ''' + Name+''' THEN Leave END) ' + QUOTENAME(Name)
FROM tblUser
INNER JOIN tblLeaveMaster ON tblUser.EmployeeID=tblLeaveMaster.EmployeeID
FOR XML PATH(''), TYPE
).value('.', 'NVARCHAR(MAX)')
,1,1,'')
SET #query= 'SELECT '+ #cols+'
FROM tblUser
INNER JOIN tblLeaveMaster ON tblUser.EmployeeID=tblLeaveMaster.EmployeeID'
execute(#query)
sqlfiddle
You can find your result from the query as shown below. Here I have taken your query output in a temporary table.
Create table #finalData(ColName Varchar(30), Leave INT)
INSERT INTO #finalData Values('Test1', 5),('Test2', 10),('Test3', 2)
DECLARE #cols AS NVARCHAR(MAX),
#query AS NVARCHAR(MAX);
SET #cols = STUFF((SELECT distinct ',' + QUOTENAME(c.ColName)
FROM #finalData c
FOR XML PATH(''), TYPE
).value('.', 'NVARCHAR(MAX)')
,1,1,'')
set #query = 'SELECT ' + #cols + ' from
(
select ColName
, Leave
from #finalData
) x
pivot
(
max(Leave)
for ColName in (' + #cols + ')
) p '
execute(#query)
DROP TABLE #finalData
Hope this will help you.
The output is as shown below
Test1 Test2 Test3
5 10 2
select pv.* from
(SELECT Name,Leave
FROM tblUser INNER JOIN tblLeaveMaster ON tblUser.EmployeeID=tblLeaveMaster.EmployeeID
)X
pivot
(max(leave) for name in ([Test1],[Test2],[Test3])) as pv
Note:- this work for me but how to use where condition base on dropdown list selected value.
eg: if wants to show only 2020 and not 2019.

Pivot table with custom Name as columnNames

How can i pivot a table with single column.
result set of my select query contains single column and 3 rows.
i.e my select query looks like :-
contactList table have following columns.
ContactID, PhNumbers, PhTYpe, ContactPersonID
select PhNumbers,PhType from contactList where ContactPersonID=3
PhNumbers PhType
1234567890 1
3456789013 2
4545466756 3
these 3 rows corresponds to 3 types of phone numbers
i need an output like this
homePhone MobilePhone WorkPhone
1234567890 3456789013 4545466756
DECLARE
#SQL varchar(MAX),
#ColumnList varchar(MAX)
SELECT #ColumnList=
COALESCE(#ColumnList + ',','') + QUOTENAME(PhNumbers)
FROM
(
SELECT DISTINCT PhNumbers
FROM contactList
) T
SET #SQL = '
WITH PivotData AS
(
SELECT PhNumbers
FROM contactList
)
SELECT
' + #ColumnList + '
FROM
PivotData
PIVOT
(
MAX(PhNumbers)
FOR PhNumbers
IN (' + #ColumnList + ')
) AS PivotResult'
EXEC (#SQL)
Got the answer. Thanks for all your help guys.
SELECT [1] as HomePhone, [2] as MobilePhone,[3] as WorkPhone,
FROM
(select PhNumbers,PhType from contactList where ContactPersonID=3) AS SourceTable
PIVOT
(
MAX(PhNumbers)
FOR PhType IN ([1],[2],[3])
) AS PivotTable;
Try this query
SELECT 1,2,3
FROM
(SELECT PhNumbers, PhType
FROM contactList where ContactPersonID=3) a
PIVOT(MAX(PhNumbers) FOR PhType IN(1,
2,
3)) r

Convert a row as column and merge two column as its value

I have stuck in a select statement, converting rows into columns. I have tried with PIVOT, i was able to convert the single column. But my requirement is little different. I have explained the requirement below.
I have a table structure as below,
I want to select the data as below,
The values in the table are dynamic, which is not a problem for me to deal with that. But i need a way to get the below result.
Could someone please give me a hint on doing it, may be a way to modify the PIVOT below.
select *
from
(
select TSID,AID,Count,BID
from tbl TS
WHERE TS.TPID = 1
) src
pivot
(
sum(Count)
for AID in (AID1,AID2,AID3)
) piv
Thank you..
You may check this fiddle
EDIT
This will work for not previously known column names
DECLARE #Columns AS VARCHAR(MAX)
DECLARE #SQL AS VARCHAR(MAX)
SELECT #Columns = STUFF(( SELECT DISTINCT ',' + AID
FROM Table1
FOR
XML PATH('')
), 1, 1, '')
SET #SQL = '
;WITH MyCTE AS
(
SELECT TSID,
AID,
STUFF(( SELECT '','' + CONVERT(VARCHAR,[Count] )
FROM Table1 I Where I.TSID = O.TSID
FOR
XML PATH('''')
), 1, 1, '''') AS CountList
FROM Table1 O
GROUP BY TSID,
AID
)
SELECT *
FROM MyCTE
PIVOT
(
MAX(CountList)
FOR AID IN
(
' + #Columns + '
)
) AS PivotTable'
EXEC(#SQL)