Replace `0` with `N/A` or `-1` in pivot query result - sql

I have Attendance table in which date and attendance is stored and I am passing date range in this query to display attendance report.
Now my question is how can I replace 0 (which I am getting as a output if the date passsed doesn't match with the date inside the Attendance table) with N/A or -1 ?
SET #query = 'SELECT RollNo,FirstName,LastName, ' + #cols + ' from
(
select S.RollNo,U.FirstName,U.LastName,
D.startdate,
convert(CHAR(10), startdate, 120) PivotDate
from #tempDates D,Attendance A, Student S, UserDetails U
where D.startdate = A.Date and A.EnrollmentNo=S.EnrollmentNo and A.EnrollmentNo=U.userID
) x
pivot
(
count(startdate)
for PivotDate in (' + #cols + ')
) p '

You could use CASE as Brandon Miller suggested. Here's another option - you can use NULLIF to replace a zero with a null value, and then replace any null value with N/A. You'll need to create a 2nd variable to represent your columns in the select statement of your dynamic query. Here's a full example with test data:
-- test data
create table #tempDates (startdate date)
create table Attendance (date date, enrollmentno int)
create table Student (rollno int, enrollmentno int)
create table UserDetails (FirstName varchar(10), LastName varchar(10), userid int)
insert into #tempDates values ('1/1/2018')
insert into Attendance values ('1/1/2018', 1)
insert into Student values (1, 1)
insert into UserDetails values ('J', 'S', 1)
declare #cols varchar(100) = '[2018-01-01],[2018-01-02]'
declare #cols_select varchar(500) = 'ISNULL(NULLIF(CAST([2018-01-01] AS VARCHAR(10)), ''0''), ''N/A'') AS [2018-01-01],ISNULL(NULLIF(CAST([2018-01-02] AS VARCHAR(10)), ''0''), ''N/A'') AS [2018-01-02]'
DECLARE #query nvarchar(max)
SET #query = 'SELECT RollNo,FirstName,LastName, '
+ #cols_select
+ 'from
(
select S.RollNo,U.FirstName,U.LastName,
D.startdate,
convert(CHAR(10), startdate, 120) PivotDate
from #tempDates D,Attendance A, Student S, UserDetails U
where D.startdate = A.Date and A.EnrollmentNo=S.EnrollmentNo and A.EnrollmentNo=U.userID
) x
pivot
(
count(startdate)
for PivotDate in (' + #cols + ')
) p '
EXEC sp_executesql #query
Outputs:
RollNo FirstName LastName 2018-01-01 2018-01-02
1 J S 1 N/A
For fun, here's a function you can use to convert the #cols variable to the #cols_select variable:
create function dbo.fn_convert_cols(#cols varchar(max)) returns varchar(max)
as
begin
declare #col varchar(20)
declare #cols_select varchar(max) = ''
declare #idx int, #idx2 int
select #idx = CHARINDEX('[', #cols), #idx2 = CHARINDEX(']', #cols)
while #idx > 0 and #idx2 > 0
begin
select #col = SUBSTRING(#cols, #idx + 1, #idx2 - #idx - 1)
select #cols_select += ',ISNULL(NULLIF(CAST([' + #col + '] AS VARCHAR(10)), ''0''), ''N/A'') AS [' + #col + ']'
select #cols = SUBSTRING(#cols, #idx2 + 1, len(#cols) - #idx2)
select #idx = CHARINDEX('[', #cols), #idx2 = CHARINDEX(']', #cols)
end
select #cols_select = SUBSTRING(#cols_select, 2, len(#cols_select) - 1)
return #cols_select
end
go
So now you can just call the function when you're building the query, like this:
SET #query = 'SELECT RollNo,FirstName,LastName, ' + dbo.fn_convert_cols(#cols)+ ' from

Related

Run query for multiple tables and columns

I have the following code, I need to run this code through over 200 tables, can I create a list and a for loop in the variable to go through all the tables and fetch the results for each? Also, how can I include the table name for each row in this query? I also need to go through a list on the column but I can't figure that out from the table list.
DECLARE #table AS VARCHAR(100)
DECLARE #column as varchar(50)
set #table = 'x'
set #column = 'y'
declare #query as varchar(max)
set #query = ' SELECT CAST(MONTH(' + #column + ') AS VARCHAR(2)) + ''-'' + CAST(YEAR(' + #column + ') AS VARCHAR(4)) as date, count(*) as SRC_CNT
FROM ' + #table +
' WHERE ' + #column + ' >= ''2018-01-01'' AND ' + #column + '< ''2021-12-01''
group BY CAST(MONTH(' + #column + ') AS VARCHAR(2)) + ''-'' + CAST(YEAR(' + #column + ') AS VARCHAR(4))
order by date;'
exec(#query)
Rather than loop, I would create a dynamic batch, with all the statements you need, which you can then execute. You can use your best friend to debug the statement(s) if needed:
DECLARE #Column sysname = N'y',
#DateFrom date = '20180101',
#DateTo date = '20211201';
DECLARE #SQL nvarchar(MAX),
#CRLF nchar(2) = NCHAR(13) + NCHAR(10);
SELECT #SQL = STRING_AGG(N'SELECT RIGHT(CONVERT(varchar(10),' + QUOTENAME(#Column) + N',105),7) AS [Date],' + #CRLF +
--N' N' + QUOTENAME(t.[name],'''') + N' AS TableName,' + #CRLF + --Uncomment this line if you need it.
N' COUNT(*) AS SRC_CNT' + #CRLF +
N'FROM ' + QUOTENAME(s.[name]) + N'.' + QUOTENAME(t.[name]) + #CRLF +
N'WHERE ' + QUOTENAME(#Column) + N' >= #DateFrom AND ' + QUOTENAME(#Column) + N' < #DateTo' + #CRLF +
N'GROUP BY RIGHT(CONVERT(varchar(10),' + QUOTENAME(#Column) + N',105),7)' + #CRLF +
N'ORDER BY [date];',#CRLF)
FROM sys.schemas s
JOIN sys.tables t ON s.schema_id = t.schema_id
WHERE EXISTS (SELECT 1
FROM sys.columns c
WHERE c.object_id = t.object_id
AND c.[name] = #Column);
--PRINT #SQL; --Your best friend
EXEC sys.sp_executesql #SQL, N'#DateFrom date, #DateTo date', #DateFrom, #DateTo;
Given tables and sample data:
CREATE TABLE dbo.x(y date, r int);
CREATE TABLE dbo.y(y date, r int);
CREATE TABLE dbo.z(y date, r int);
INSERT dbo.x(y,r) VALUES('20180105',5),
('20180107',6),('20180509',7);
INSERT dbo.y(y,r) VALUES('20180905',5),
('20181007',6),('20181009',7);
INSERT dbo.z(y,r) VALUES('20180605',5),
('20180607',6),('20180609',7);
This dynamic SQL can be generated:
DECLARE #col sysname = N'y',
#StartDate date = '20180101',
#EndDate date = '20211201';
DECLARE #sql nvarchar(max) = N'',
#base nvarchar(max) = N'SELECT [Table Name] = $tblQ$,
[date] = DATEFROMPARTS(YEAR($col$), MONTH($col$), 1),
SRC_CNT = COUNT(*)
FROM dbo.$tbl$ WHERE $col$ >= #s AND y < #e
GROUP BY YEAR($col$), MONTH($col$)';
SELECT #sql = STRING_AGG(REPLACE(REPLACE(REPLACE
(#base, N'$tblQ$', QUOTENAME(t.name, char(39))
),N'$tbl$',QUOTENAME(t.name)), N'$col$', #col), N'
UNION ALL
') + ' ORDER BY [date];'
FROM sys.tables AS t
WHERE EXISTS (SELECT 1 FROM sys.columns
WHERE [object_id] = t.[object_id]
AND name = #col);
PRINT #sql;
EXEC sys.sp_executesql #sql,
N'#s date, #e date',
#StartDate, #EndDate;
Which produces a query like this (only tables that actually have that column name, could be made even safer by making sure they're using a date/time type):
SELECT [Table Name] = 'x',
[date] = DATEFROMPARTS(YEAR(y), MONTH(y), 1),
SRC_CNT = COUNT(*)
FROM dbo.[x] WHERE y >= #s AND y < #e
GROUP BY YEAR(y), MONTH(y)
UNION ALL
SELECT [Table Name] = 'y',
[date] = DATEFROMPARTS(YEAR(y), MONTH(y), 1),
SRC_CNT = COUNT(*)
FROM dbo.[y] WHERE y >= #s AND y < #e
GROUP BY YEAR(y), MONTH(y)
UNION ALL
SELECT [Table Name] = 'z',
[date] = DATEFROMPARTS(YEAR(y), MONTH(y), 1),
SRC_CNT = COUNT(*)
FROM dbo.[z] WHERE y >= #s AND y < #e
GROUP BY YEAR(y), MONTH(y) ORDER BY [date];
That generates output like this:
Table Name
date
SRC_CNT
x
2018-01-01
2
x
2018-05-01
1
z
2018-06-01
3
y
2018-09-01
1
y
2018-10-01
2
Example db<>fiddle
If you really want yyyy-MM instead of yyyy-MM-dd on the output, you can just change this line in the declaration of #base:
[date] = CONVERT(char(7), DATEFROMPARTS(YEAR($col$), MONTH($col$), 1), 120),
And I realized the requirement was MM-yyyy, in which case:
[date] = RIGHT(CONVERT(char(10),
DATEFROMPARTS(YEAR($col$), MONTH($col$), 1), 105), 7),
I usually do the following for tables:
SELECT TABLE_NAME
FROM [<DATABASE_NAME>].INFORMATION_SCHEMA.TABLES
WHERE TABLE_TYPE = 'BASE TABLE'
You said you could handle columns from there.

Join using dynamic column names SQL Server

I have a table which can output any number of different columns (from 'Level1' to 'Level'N).
I need to perform a left join on each of these dynamic columns against a CTE
I have written the following script but keep getting this error:
Msg 102, Level 15, State 1, Line 15 Incorrect syntax near '10'.
To troubleshoot, I have tried removing the each of the variables in the CTE with no luck.
Any help would be much appreciated!
DECLARE #rel varchar(4) = CAST('X112' AS varchar(4))
DECLARE #todaysdate date = CONVERT(date,GETDATE())
--create cte
DECLARE #sqltext varchar(MAX) =
' WITH CTE AS
(
SELECT
ID
,STARTDATE
,ENDDATE
,NEWID
FROM Tbl
WHERE TYPE = ''' + #rel + '''
AND ENDDATE >= ' + CAST(#todaysdate AS varchar(30)) +' AND STARTDATE <= ' + CAST(#todaysdate AS varchar(30)) +'
)
SELECT ID, NEWID, Level';
--find max lvl, convert to str
DECLARE #counter int = (SELECT MAX(lvl) FROM tbl2)
DECLARE #counterstring varchar(3)
SET #counterstring = CAST(#counter AS varchar(3))
WHILE #counter != 0
BEGIN
SET #sqltext = #sqltext + #counterstring + ' INTO tbl3 '
+ ' FROM tbl2 a '
+ ' LEFT JOIN CTE c ON a.Level' + #counterstring + ' = c.NEWID'
SET #counter = #counter - 1
END
EXEC(#sqltext)
--edited version
DECLARE #rel varchar(4) = CAST('X112' AS varchar(4))
DECLARE #todaysdate date = CONVERT(date,GETDATE())
DECLARE #sqltext varchar(MAX) =
' WITH CTE AS
(
SELECT
ID
,STARTDATE
,ENDDATE AS mgmt_ENDDA
,NEWID
FROM tbl
WHERE SUBTY = ''' + #rel + '''
AND ENDDATE >= ' + CAST(#todaysdate AS varchar(30)) +' AND STARTDATE <= ' + CAST(#todaysdate AS varchar(30)) +'
)
INSERT INTO tbl3
SELECT ID, NEWID, Level';
DECLARE #counter int = (SELECT MAX(lvl) FROM tbl2)
DECLARE #counterstring varchar(3)
WHILE #counter != 0
BEGIN
SET #counterstring = CAST(#counter AS varchar(3))
SET #sqltext = #sqltext + #counterstring
+ ' FROM tbl2 a '
+ ' LEFT JOIN CTE c ON a.Level' + #counterstring + ' = c.NEWID'
SET #counter = #counter - 1
END
EXEC(#sqltext)
Since select * into query creates a new table each time, I am assuming that you are trying to create 'n' number of tables for 'n' number of levels, with the result obtained by joining with nth column. I have 2 suggestions for you
Bring the select query within the while loop and append ';' at the end of the loop to split select queries.
instead of INTO tbl3 use INTO tbl + #counterstring as select * into will create new table
Hope this helps you
Can you change it like this and try again?
--edited version
DECLARE #rel varchar(4) = CAST('A012' AS varchar(4))
DECLARE #todaysdate date = CONVERT(date,GETDATE())
DECLARE #sqltext varchar(MAX) =
' WITH CTE AS
(
SELECT
ID
,STARTDATE
,ENDDATE AS mgmt_ENDDA
,NEWID
FROM tbl
WHERE SUBTY = ''' + #rel + '''
AND ENDDATE >= ' + CAST(#todaysdate AS varchar(30)) +' AND STARTDATE <= ' + CAST(#todaysdate AS varchar(30)) +'
)
INSERT INTO tbl3';
DECLARE #counter int = (SELECT MAX(lvl) FROM tbl2)
DECLARE #counterstring varchar(3)
WHILE #counter != 0
BEGIN
SET #counterstring = CAST(#counter AS varchar(3))
SET #sqltext = #sqltext + CHAR(10) +'SELECT ID, NEWID, Level'+#counterstring
SET #sqltext = #sqltext + ' FROM tbl2 a '
+ ' LEFT JOIN CTE c ON a.Level' + #counterstring + ' = c.NEWID'
SET #counter = #counter - 1
IF #counter <> 0
SET #sqltext = #sqltext + CHAR(10) + ' UNION '
END
EXEC(#sqltext)
You can try 'UNION ALL' instead of 'UNION' if you dont want to get rid of duplicate data. Hope this helps

Dynamic pivot a 3 column table

I'm trying to use dynamic pivot to have a column containing dates to be the column names.
I want this table:
App Date Count
Excel 2018-05-01 1
Excel 2018-05-02 1
Excel 2018-05-03 2
Word 2018-05-02 3
Word 2018-05-07 5
Word 2018-05-12 2
Paint 2018-05-07 6
to look like this:
2018-05-01 2018-05-02 2018-05-03 2018-05-07 2018-05-12
Excel 1 1 2 0 0
Word 0 3 0 5 2
Paint 0 0 0 6 0
I can't use a normal pivot as I don't know how many or what the dates will actually be. Each app can have a different number of rows. This table isn't just a SELECT * FROM TABLE either, it's made up of subqueries and CTEs so is a little complicated to work with.
Any help is appreciated. Let me know if you need more information.
Using dynamic TSQL:
if OBJECT_ID('dbo.test') is null
create table dbo.test(App varchar(50), [Date] varchar(50), [Count] int)
truncate table dbo.test
insert into dbo.test values
('Excel', '2018-05-01', 1),
('Excel', '2018-05-02', 1),
('Excel', '2018-05-03', 2),
('Word ', '2018-05-02', 3),
('Word ', '2018-05-07', 5),
('Word ', '2018-05-12', 2),
('Paint', '2018-05-07', 6)
declare #dates nvarchar(max)='' --holds all the dates that will become column names
declare #dates_aliases nvarchar(max)='' --holds the headers without NULL values
declare #sql nvarchar(max)='' --contains the TSQL dinamically generated
select #dates = #dates + ', [' + CONVERT(char(10), [date],126)+ ']' from dbo.test
group by [date]
select #dates_aliases = #dates_aliases + ', isnull(['
+ CONVERT(char(10), [date],126)+ '], 0) as ['
+ CONVERT(char(10), [date],126)+ ']'
from dbo.test group by [date]
set #dates = RIGHT(#dates, len(#dates)-2)
set #dates_aliases = RIGHT(#dates_aliases, len(#dates_aliases)-2)
set #sql = #sql + ' select piv.[App], ' + #dates_aliases
set #sql = #sql + ' from '
set #sql = #sql + ' ( '
set #sql = #sql + ' select [App], [Date], [Count] '
set #sql = #sql + ' from dbo.test '
set #sql = #sql + ' ) src '
set #sql = #sql + ' pivot '
set #sql = #sql + ' ( '
set #sql = #sql + ' max([Count]) '
set #sql = #sql + ' for [Date] in ('+#dates+') '
set #sql = #sql + ' ) piv '
exec(#sql)
Results:
Try this:
SELECT A.*
INTO #TEMP
FROM
(
SELECT 'Excel' as app,'2018-05-01' as 'Date',1 as 'Count'
UNION ALL
SELECT 'Excel' as app,'2018-05-02' as 'Date',1 as 'Count'
UNION ALL
SELECT 'Excel' as app,'2018-05-03' as 'Date',2 as 'Count'
UNION ALL
SELECT 'Word' as app,'2018-05-02' as 'Date', 3 as 'Count'
UNION ALL
SELECT 'Word' as app,'2018-05-07' as 'Date', 5 as 'Count'
UNION ALL
SELECT 'Word' as app,'2018-05-12' as 'Date', 2 as 'Count'
UNION ALL
SELECT 'Paint' as app,'2018-05-07' as 'Date', 6 as 'Count'
) as A
ANSWER:
DECLARE #SQL VARCHAR(MAX)
DECLARE #Columns VARCHAR(MAX) = ''
DECLARE #Columns2 VARCHAR(MAX) = ''
SELECT #Columns = #Columns + '[' + a.[Column] + '], '
FROM
(SELECT DISTINCT [date] as [Column]
FROM #TEMP) as a
SELECT #Columns2 = #Columns2 + 'ISNULL([' + a.[Column] + '],0) as [' + a.[column] +'], '
FROM
(
SELECT DISTINCT [date] as [Column]
FROM #TEMP
) as a
SET #Columns2 = Left(#Columns2, Len(#Columns2) - 1)
SET #Columns = Left(#Columns, Len(#Columns) - 1)
SET #SQL = 'SELECT app, ' + #Columns2
+ ' FROM #TEMP PIVOT (Avg (Count) FOR Date IN ('
+ #Columns
+ ')) AS pt '
--PRINT #Columns
EXEC( #SQL )

How to provide custom name to column in pivoting

I have a table like this:
id unit
1 mm
2 cm
3 kg
When I perform pivot operation on this, I am getting result as follows:
1 2 3
mm cm kg
Is it possible to get custom column names here, something like this:
d1 d2 d3
mm cm kg
I am using Pivot for this as:
IF OBJECT_ID('tempdb..#t') IS NOT NULL
DROP TABLE #t
GO
CREATE table #t
(id varchar(max),unit varchar(max))
insert into #t (id,unit)values
(1,'kg'),
(2,'cm'),
(3,'mm'),
(4,'m')
DECLARE #statement NVARCHAR(max)
,#columns NVARCHAR(max)
SELECT #columns = ISNULL(#columns + ',', '') + N'[' + cast(tbl.id as varchar(max)) + ']'
FROM (
SELECT DISTINCT id
FROM #t
) AS tbl
SELECT #statement = 'select *
INTO ##temp
from (
SELECT id,[unit]
FROM #t
) as s
PIVOT
(max(unit) FOR id in(' + #columns + ')) as pvt
'
EXEC sp_executesql #statement = #statement
SELECT * FROM ##temp
DROP TABLE #t
DROP TABLE ##temp
Is it possible?
Thanks
IF OBJECT_ID('tempdb..#t') IS NOT NULL
DROP TABLE #t
GO
CREATE TABLE #t (
id VARCHAR(10),
unit VARCHAR(100)
)
INSERT INTO #t (id, unit)
VALUES
('1', 'kg'),
('2', 'cm'),
('3', 'mm'),
('4', 'mm')
DECLARE #SQL NVARCHAR(MAX), #columns NVARCHAR(MAX)
SELECT #columns = STUFF((
SELECT ',[D' + id + ']'
FROM #t
FOR XML PATH('')), 1, 1, '')
SELECT #SQL = '
SELECT *
FROM (
SELECT [unit], col = N''D'' + id
FROM #t
) s
PIVOT (MAX(unit) FOR col IN (' + #columns + ')) p'
EXEC sys.sp_executesql #SQL
Just add a prefix to your ID. Example
SELECT #statement = 'select * INTO ##temp from
( SELECT [id] = ''d''+id,[unit] FROM #t ) as s
PIVOT
(max(unit) FOR id in(' + #columns + ')) as pvt '
Also it's terrible practice to use global temp tables! Especially one named ##temp
You can use a CASE expression with a dynamic sql query.
CREATE TABLE #t
(
id INT,
unit VARCHAR(2)
);
INSERT INTO #t VALUES
(1,'mm'),
(2,'cm'),
(3,'kg');
DECLARE #query AS VARCHAR(MAX);
SELECT #query = 'SELECT ' +
STUFF
(
(
SELECT DISTINCT ',MAX(CASE WHEN id = '+ CAST(id AS VARCHAR(10))
+ ' THEN unit END) AS d' + CAST(id AS VARCHAR(10))
FROM #t
FOR XML PATH('')
),
1,1,'');
SELECT #query += ' FROM #t;';
EXECUTE(#query);
Result
+----+----+----+
| d1 | d2 | d3 |
+----+----+----+
| mm | cm | kg |
+----+----+----+
SELECT #statement = 'select * INTO ##temp from ( SELECT ''d''+id AS [id],[unit] FROM #t ) as s PIVOT (max(unit) FOR id in(' + #columns + ')) as pvt '

Loop through column values in Temp Table with N columns

I have a scenario inside a stored procedure where a temporary table will be generated with an unknown number of columns (Column1.....ColumnN). One of the columns will be the total\sum of few of the other columns.
The clients requirement is to show the percentage value of each column in comparison to the total column
(C1*100)/Total as P1 ,(C2*100)/Total as P2.....
I have really been unable to find a solution to this problem other than doing it in the front end using LINQ. I am wondering if there is any way to achieve this in SQL as that would give me performance benefits.The last thing I want to do is to loop through the rows and columns in C# which will hammer the server.
I had done, I just change according to you and you can read the comment for better understand. I feel the schemaname is dbo, else change it.
-------------1. first step --------------
--create table for exercise
CREATE TABLE [dbo].[tblTest](
[ID] [int] NULL,
[isTrue] [bit] NULL
) ON [PRIMARY]
--insert date
insert into tblTest values(1,'true'),(2,'false'),(3,'false'),(4,'true'),(5,'false')
select * from tbltest
-------------2. second step --------------
--now start to get column name one by one
DECLARE #TableName nvarchar(256) = '[dbo].[tblTest]',
#SearchStr nvarchar(128)='id', #SearchStr2 nvarchar(110) --this is used to get only particular column result, to check remove uncomment in cursor
SET #SearchStr2 = QUOTENAME('%' + #SearchStr + '%','''')
DECLARE #Columnname varchar(100) ,#ColumnIndex int --, #PurchaseQty int -- declare temp variable which you u
CREATE TABLE #Results (ColumnName nvarchar(370), ColumnValue nvarchar(3630), ColIndex int)
DECLARE getItemID CURSOR
FOR
select column_name, ordinal_position from INFORMATION_SCHEMA.COLUMNS where TABLE_NAME = PARSENAME(#TableName, 1)
OPEN getItemID
FETCH NEXT FROM getItemID INTO #Columnname, #ColumnIndex
WHILE ##FETCH_STATUS = 0
BEGIN
--select #Columnname, #ColumnIndex ;
INSERT INTO #Results
EXEC
(
'SELECT ''' + #ColumnName + ''', LEFT(' + #ColumnName + ', 3630) , '+ #ColumnIndex +'
FROM ' + #TableName + ' (NOLOCK) '
--remove this to get only particular column entry
--+' WHERE ' + #ColumnName + ' LIKE ' + #SearchStr2
)
FETCH NEXT FROM getItemID INTO #Columnname, #ColumnIndex
END
CLOSE getItemID
DEALLOCATE getItemID
select * from #Results
drop table #Results
DECLARE #cols AS NVARCHAR(max),
#calCols AS NVARCHAR(max),
#query AS NVARCHAR(max)
SELECT *
INTO #temptable
FROM (SELECT journeyid,
notchl,
Cast(Sum(Datediff(second, starttime, endtime)) AS FLOAT) AS
Duration
FROM (SELECT notchlog.*,
CASE
WHEN ( Isnumeric(notch) = 1
AND notch < 0 ) THEN 'DYN'
WHEN notch = 'I' THEN 'IDLE'
WHEN notch = 'C' THEN 'COASTING'
ELSE 'N' + notch
END AS NotchL
FROM notchlog)Sub1
GROUP BY journeyid,
notchl)SUB1
SELECT #cols = Stuff(( SELECT ',' + Quotename(notchl)
FROM #temptable
GROUP BY notchl
--order by value
FOR XML PATH(''), TYPE
).value('.', 'NVARCHAR(MAX)')
, 1, 1, '')
SELECT #calCols = Stuff((SELECT ',' + 'ROUND(' + Quotename(notchl)
+ '*100/RunningTime,2) as '
+ Quotename(notchl)
FROM #temptable
GROUP BY notchl
--order by value
FOR XML PATH(''), TYPE
).value('.', 'NVARCHAR(MAX)')
, 1, 1, '')
SET #query =N'Select * INTO #ResultTable FROM( SELECT Journeyid, '
+ #cols + ' from ( select Journeyid, NotchL, Duration from #TempTable Group By JourneyId,NotchL,Duration ) x pivot ( max(x.duration) for NotchL in ('
+ #cols
+ ') ) p ) Sub2 select NL.JourneyId,RunningTime,'
+ #calCols
+ N' from #ResultTable R INNER Join (Select JourneyID,Sum(DateDiff(second,starttime,endtime)) as RunningTime FROM NotchLog Group By JourneyID)NL ON NL.JourneyID=R.JourneyId INNER Join Journeys J ON J.JourneysID=R.JourneyID Drop Table #ResultTable '
EXEC Sp_executesql
#query;
DROP TABLE #temptable