Related
I have a simple table. As a result I need to get names of numeric columns and paste like rows and then paste its values like columns.Here is an example of table:
As a result I need to receive something like this:
I tried to get the result with PIVOT, but I have not the correct answer.
select * from (
select col1, 'val' + cast(row_number()over(partition by col1 order by col1) as nvarchar(20)) ColVal
from mytbl
) tmp
pivot (
min(col1) for ColVal in (val1,val2)
) pvt
In this case you need to unpivot first, then pivot back:
DROP TABLE IF EXISTS dbo.temp
DROP TABLE IF EXISTS dbo.temp2
CREATE table dbo.temp(col1 INT, col2 INT, col3 INT);
INSERT INTO temp VALUES (27,93,80),(32,84,72),(46,68,75),(38,79,73),(23,77,84);
DECLARE #colsUnpivot AS NVARCHAR(MAX),
#query AS NVARCHAR(MAX)
-- first unpivot to key value pairs
select #colsUnpivot
= stuff((select ','+quotename(C.column_name)
from information_schema.columns as C
where C.table_name = 'temp' and
C.column_name like 'col%'
for xml path('')), 1, 1, '')
set #query
= 'SELECT ''val'' + convert(varchar, i) as id,
name,
val
INTO dbo.temp2
FROM
(
SELECT *, row_number() over (order by col1) as i
from temp
) a
UNPIVOT
(
val
FOR name IN ('+ #colsunpivot +')
) u'
exec sp_executesql #query;
-- now pivot back
DECLARE #columns NVARCHAR(MAX), #sql NVARCHAR(MAX);
SET #columns = N'';
SELECT #columns += N', ' + QUOTENAME(id)
FROM (SELECT DISTINCT id FROM dbo.temp2) AS x;
SET #query = N'
SELECT name, ' + STUFF(#columns, 1, 2, '') + '
FROM
(
SELECT id, name, val
from temp2
) AS j
PIVOT
(
SUM(val) FOR id IN ('
+ STUFF(REPLACE(#columns, ', [', ',['), 1, 1, '')
+ ')
) AS p;';
EXEC sp_executesql #query;
I adapted two separate scripts I had lying around, hence the two parts and the intermediate temp2 table. You can probably mash both together with a bit of elbow grease, but this should get you most of the way there.
Also adding the id (to get val1, val2 etc) dynamically means the results are sorted by col1 (val1 will have the lowest col1) but you were doing something similar in your attempt so I assume this is ok. If not, you will need to add an identity column to the data first and use that in place of the row_number()
i have data in below format. this data is coming through SQL Query.
i want to show it in below format either by query or by rdlc report.
You need to use dynamic SQL to make it.
From your expected result you can try to follow thoes step to make it.
use row_number function make row number by Name, because we need to join base on that row_number.
get the use MAX and MIN to make row number calendar table. from 1 to max(rn). the table can let use outer join
declare a var #tables to make the OUTER JOIN execute SQL (each LEFT JOIN maen a group of Crew#).
declare a var #col to make column, which you want to select (Employee) from each table.
then use execute dynamic execute it.
look like this.
create table T
(
Name varchar(50),
Employee VARCHAR(50)
)
insert into T values ('Crew#1','TR123');
insert into T values ('Crew#1','311');
insert into T values ('Crew#2','DDD');
insert into T values ('Crew#2','12121');
insert into T values ('Crew#1','SDDAS');
insert into T values ('Crew#3','31114312');
insert into T values ('Crew#3','DD14124D');
insert into T values ('Crew#3','1214124121');
insert into T values ('Crew#3','SDD412AS');
DECLARE #tables AS NVARCHAR(MAX),
#query AS NVARCHAR(MAX),
#col AS NVARCHAR(MAX);
SET #tables = STUFF((SELECT distinct ' LEFT JOIN ' + ' (SELECT * FROM CTE WHERE Name = '''+Name+''') '+QUOTENAME(Name)+' on t1.smallRN = '+QUOTENAME(Name)+'.rn'
FROM T
FOR XML PATH(''), TYPE
).value('.', 'NVARCHAR(MAX)')
,1,1,'')
SET #col = STUFF((SELECT distinct ', ' + QUOTENAME(Name)+'.Employee as '''+ QUOTENAME(Name) +''''
FROM T
FOR XML PATH(''), TYPE
).value('.', 'NVARCHAR(MAX)')
,1,1,'')
SET #col = substring(#col,1, len(#col))
set #query = '
WITH CTE AS (
SELECT *,ROW_NUMBER() OVER(PARTITION BY Name ORDER BY Name) rn
FROM T
),CTE1 AS(
SELECT MIN(rn) smallRN,MAX(rn) bigRN
FROM CTE
UNION ALL
SELECT smallRN+1,bigRN
FROM CTE1
WHERE smallRN < bigRN
)
SELECT '+#col+'
FROM CTE1 t1 ' + #tables
execute(#query)
sqlfiddle
Creatin tbale
First we will create a temp table where we will stock the data that you have and your table
create table #table1
(
[Crew Name] varchar(500) ,
Employee varchar(500)
)
INsert into #table1
values (....)
select * from #table1
Dynamic selection
then we will create a dynamic query to get the columns that we have, that way we can add as much crews as we want,
declare #DynamicPivotQuery as nvarchar(max)
declare #ColumnName as nvarchar(max)
select #ColumnName = ISNULL(#ColumnName +',','') + QUOTENAME([Crew Name])
from (select distinct [Crew Name] from #table1) as Country
set #DynamicPivotQuery = N'select ' +#ColumnName + '
from #table1
Pivot ( MAX(Employee)
FOR [Crew Name] in (' +#ColumnName+')) as Pivoted
'
exec (#DynamicPivotQuery)
this way we will get only the first row for every column
so we have to find a way to aggregate and get the other columns as well just to demonstrate i will union the Mmin also this is where i stoped my testes but you can do more then this with some testes
now the union :
declare #DynamicPivotQuery as nvarchar(max)
declare #ColumnName as nvarchar(max)
select #ColumnName = ISNULL(#ColumnName +',','') + QUOTENAME([Crew Name])
from (select distinct [Crew Name] from #table1) as Country
set #DynamicPivotQuery = N'select ' +#ColumnName + '
from #table1
Pivot ( MAX(Employee)
FOR [Crew Name] in (' +#ColumnName+')) as Pivoted
union
select ' +#ColumnName + '
from #table1
Pivot ( MIN(Employee)
FOR [Crew Name] in (' +#ColumnName+')) as Pivoted
'
exec (#DynamicPivotQuery)
here is the result :
if you follow this way i'm sure that you will find a way to union all the result
You can add this result into a temp table
then add a column which will be a reference into this temp table
then use pivot function
To know more about pivot Visit :
https://msdn.microsoft.com/en-us/azure/data-lake-analytics/u-sql/pivot-and-unpivot-u-sql
you can use also SSIS to a very handy tool and easy to use
Using dynamic PIVOT if you dont have a set Crew columns.
DECLARE #ColumnString VARCHAR(256)
DECLARE #ColumnHeadrer VARCHAR(256)
DECLARE #sql varchar(1000)
CREATE TABLE #ColumnValue
(
Value VARCHAR(500),
ColumnHeader VARCHAR(256)
)
INSERT INTO #ColumnValue (Value, ColumnHeader)
SELECT DISTINCT '[' + CrewName + ']',
'ISNULL(' + CrewName + ','''') AS ' + CrewName
FROM CrewTable
SELECT #ColumnString = COALESCE(#ColumnString + ',', '') + Value,
#ColumnHeadrer = COALESCE(#ColumnHeadrer + ',', '') + ColumnHeader
FROM #ColumnValue
SET #sql =
'
SELECT ' + #ColumnHeadrer + '
FROM
(
SELECT Employee,
CrewName,
ROW_NUMBER() OVER(PARTITION BY CrewName ORDER BY CrewName) AS rnk
FROM CrewTable
) AS P
PIVOT
(
MAX(Employee) FOR [CrewName] IN ('+#ColumnString+')
) AS pv
'
EXEC (#sql)
I have two tables. I write a query. Date is dynamic. I can select any date. `
select a.MP,a.CP,a.Frequency,a.Time,CONVERT(varchar(12),b.date,101) as
EntryDate,b.actualtime from mpcp a, DailyData b
where a.UserID=1 and a.MpCpId=b.MpCpId and
CONVERT(varchar(12),b.EntryDate,101) between
CONVERT(varchar(12),GETDATE()-5,101) and
CONVERT(varchar(12),GETDATE()+25,101)`
Output
But i want output like
Assuming that i am storing your result in one temp table and imaging data i created one data for your requirement
try this one whether it is useful or not
create table #piv
(
mp varchar(10),
cp varchar(10),
freq varchar(10),
time int,
entryd date,
acuralize int
)
insert into #piv values
('don','asper','da',30,getdate(),0),
('dwm','donl','da',10,getdate(),3),
('qar','qpr','da',15,getdate(),5),
('qar','qpr','da',15,'01-16-17',5),
('qar','qpr','da',15,'01-15-17',5),
('qar','qpr','da',15,'01-16-17',5)
SELECT * FROM #piv
Declare #SQL varchar(max) = Stuff((Select Distinct ',' + QuoteName(entryd) From #piv Order by 1 For XML Path('')),1,1,'')
Select #SQL = '
Select *,' + #SQL + '
From #piv
Pivot (max(time) For [entryd] in (' + #SQL + ') ) p'
Exec(#SQL);
You can create a dynamic pivot. A good example is available on this link.
Good Luck !
DECLARE #cols VARCHAR(max),#sql VARCHAR(max)
SELECT #cols=ISNULL(#cols+',[','[')+ CONVERT(VARCHAR,a.EntryDate,101)+']'
FROM mpcp a, DailyData b
where a.UserID=1 and a.MpCpId=b.MpCpId and DATEDIFF(d,GETDATE(),b.EntryDate) BETWEEN -5 AND 25
GROUP BY a.time
SET #sql='
SELECT * FROM (
SELECT a.MP,a.CP,a.Frequency,a.Time,CONVERT(varchar(12),b.date,101) AS EntryDate,b.actualtime
FROM mpcp a, DailyData b
WHERE a.UserID=1 and a.MpCpId=b.MpCpId and where a.UserID=1 and a.MpCpId=b.MpCpId and DATEDIFF(d,GETDATE(),b.EntryDate) BETWEEN -5 AND 25
) AS t
PIVOT (MAX(actualtime) FOR EntryDate IN ('+#cols+') )'
EXEC(#sql)
I have two tables MasterTableTest8 and HistoricDatatest8.
create table MasterTableTest8
(ID int primary key, Name varchar(10))
insert into MasterTableTest8 values (1,'ATS')
insert into MasterTableTest8 values (2,'BTS')
CREATE TABLE HistoricDatatest8
(
ID int FOREIGN KEY REFERENCES MasterTableTest8(ID),
Name varchar(100),
ShortName varchar(10),
Reason varchar(10),
Importance varchar(10),
Noofissues int,
inserteddate datetime
)
insert into HistoricDatatest8 values (1,'ATS','S', 'Other','High',26,getdate()-7)
insert into HistoricDatatest8 values (1,'ATS','S', 'Other','High',8,getdate()+7)
insert into HistoricDatatest8 values (1,'ATS','S', 'Other','High',80,getdate())
insert into HistoricDatatest8 values (2,'BTS','S1', 'Other','LOW',26,getdate()-7)
insert into HistoricDatatest8 values (2,'BTS','S1', 'Other','LOW',8,getdate()+7)
insert into HistoricDatatest8 values (2,'BTS','S1', 'Other','LOW',80,getdate())
--Created and inserted two tables.
select
N.ID,
N.Name,
ShortName,
Reason,
Importance,
Noofissues,
inserteddate
INTO #TABLE
FROM HistoricDatatest8 N
JOIN MasterTableTest S ON N.ID=S.ID
--Inserting the required data in the Hash table.
--drop table #table
DECLARE #cols NVARCHAR (MAX)
SELECT #cols = COALESCE (#cols + ',[' + CONVERT(NVARCHAR, [inserteddate], 106) + ']',
'[' + CONVERT(NVARCHAR, [inserteddate], 106) + ']')
FROM (SELECT DISTINCT [inserteddate] FROM #TABLE) PV
ORDER BY [inserteddate]
DECLARE #query NVARCHAR(MAX)
SET #query = '
SELECT * FROM
(
SELECT * FROM #TABLE
) x
PIVOT
(
count(Noofissues)
FOR [inserteddate] IN (' + #cols + ')
) p'
EXEC SP_EXECUTESQL #query
Current Result
Expected Result:
What is your expected result? Your current display shows the same current and expected result.
Are you expecting:
Date | Name | ShortName | Reason | Importance | Number of Issues|
05-Jul-16 | ATS | S| Other| High|26
12-Jul-16|BTS |S1| Other | LOW|80
After lots of R & D i got this result, might be useful to some others. if any optimized answer will be appreciated.
select * from HistoricDatatest80 order by ID
select N.ID,N.Name,ShortName,Reason,Importance,Noofissues,inserteddate INTO #TABLE FROM HistoricDatatest80 N JOIN MasterTableTest80 S ON N.ID=S.ID
--drop table #table
DECLARE #cols NVARCHAR (MAX)
SELECT #cols = COALESCE (#cols +',','')+ '['+DATEValue+']'
FROM (SELECT DISTINCT (CONVERT(NVARCHAR, [inserteddate], 106)) AS DATEValue FROM HistoricDatatest80) PV
ORDER BY DATEValue
print #cols
DECLARE #query NVARCHAR(MAX)
SET #query = '
SELECT * FROM
(
SELECT ShortName,Reason,Importance,Noofissues,(CONVERT(NVARCHAR, [inserteddate], 106)) AS DATEValue FROM #TABLE
) x
PIVOT
(
sum(Noofissues)
FOR [DATEValue] IN (' + #cols + ')
) p'
EXEC SP_EXECUTESQL #query
drop table #table
I have a dataset like this
[student][datetime][dictionary][value]
[1234 ][datetime][1 ][a ]
[1234 ][datetime][2 ][b ]
I want to create a dataset like this
[student][1 ][2 ]
[1234 ][a ][b ]
I understand that SQL Server pivots are a way to accomplish this. I've written the below code to attempt to pivot the data however, it's naturally not grouped.
So my results end up like this:
[student][datetime][1 ][2 ]
[1234 ][datetime][null ][b ]
[1234 ][datetime][a ][null ]
How can I best group these? I don't care about having the other source columns such as datetime in the final dataset, only the matrix of dictionaries and values
Thank you
DECLARE #columns AS VARCHAR(MAX);
DECLARE #sql AS VARCHAR(MAX);
SELECT #columns = substring((Select DISTINCT ',' + QUOTENAME(dictionary) FROM syuservalues FOR XML PATH ('')),2, 1000);
SELECT #sql =
'SELECT Pivoted.*
FROM syuservalues
PIVOT
( MAX(value)
FOR dictionary IN( ' + #columns + ' )) as Pivoted where student = 327392'; ' Will eventually want it for all students
EXECUTE(#sql);
a and b is brought to two rows because, you have added [datetime] column for pivot and the [datetime] value for a and b will be different.
SAMPLE TABLE
CREATE TABLE #TEMP([student] INT,[datetime] DATETIME,[dictionary] INT,[value] VARCHAR(30))
INSERT INTO #TEMP
SELECT 1234,'2015-02-01',1,'a'
UNION ALL
SELECT 1234, '2015-02-01',2,'b'
Declare a variable to get columns for pivot dynamically
DECLARE #cols NVARCHAR (MAX)
SELECT #cols = COALESCE (#cols + ',[' + CAST([dictionary] AS VARCHAR(10)) + ']',
'[' + CAST([dictionary] AS VARCHAR(10)) + ']')
FROM
(
SELECT DISTINCT [dictionary]
FROM #TEMP
) PV
ORDER BY CAST([dictionary] AS INT)
Now pivot it. I have written the logic inside.
DECLARE #query NVARCHAR(MAX)
SET #query = '-- Your pivoted result is here
SELECT *
FROM
(
-- Select data before pivot. We are not taking [datetime] column because
-- it will not bring ur expected result
SELECT student,[dictionary],value
FROM #TEMP
) x
PIVOT
(
-- Value in each dynamic column
MIN(value)
-- Tell the columns to pivot
FOR [dictionary] IN (' + #cols + ')
) p
ORDER BY student;'
EXEC SP_EXECUTESQL #query
For this kind of problem, you can just use an arbitrary aggregate function so that you get rid of the nulls. I usually use max because it can be used on both numeric and string data types.
select pivoted.student, [1] = max([1]), [2] = max([2])
from syuservalues
pivot(max(value) for dictionary in(...)) pivoted
group by pivoted.student