Displaying Rows as Columns With Total Displayed on Each Row and Column

Scenario

I have a table with the following columns as in the following:

CREATE TABLE [dbo].[TimeLogging](

      [ID] [int] NOT NULL,

      [Date] [date] NULL,

      [timelogged] [decimal](18, 2) NULL,

      [username] [varchar](50) NULL,

 CONSTRAINT [PK_TimeLogging] PRIMARY KEY CLUSTERED

(

      [ID] ASC

)WITH (PAD_INDEX  = OFF, STATISTICS_NORECOMPUTE  = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS  = ON, ALLOW_PAGE_LOCKS  = ON) ON [PRIMARY]

) ON [PRIMARY]

I have data something as in the following:

ID Date timelogged username
1 2012-10-08 5.50 Ravi
2 2012-11-08 2.30 Ravi
3 2012-10-08 3.30 Joe
4 2012-11-08 7.30 Joe
5 2012-11-09 8.30 Marie
6 2012-12-05 99.90 John
7 2009-06-09 78.78 Kelly

Problem Statement

I want this data to be displayed with all the user names as columns in the results with a unique date displayed in each row and show the total on each row and column. The output should be as in the following:

Date Ravi Marie Kelly John Joe Total
06/09/2009 0.00 0.00 78.78 0.00 0.00 78.78
10/08/2012 5.50 0.00 0.00 0.00 3.30 8.80
11/08/2012 2.30 0.00 0.00 0.00 7.30 9.60
11/09/2012 0.00 8.30 0.00 0.00 0.00 8.30
12/05/2012 0.00 0.00 0.00 99.90 0.00 99.90
Total 78.78 8.30 78.78 99.90 10.60 205.38

Solution

You can uncomment the SELECT statement to check what is happening at each step. We are using Dynamic SQL for displaying the data. Feel free to uncomment anytime in the query and see what is happening.

DECLARE @Count INT = 1

DECLARE @MaxCount INT = 0

 

---TABLE TO STORE THE USERNAMES IN A SEPERATE TABLE VARIABLE

DECLARE @ColumnNames Table

(

      ID INT PRIMARY KEY IDENTITY(1,1),

      ColumnName VARCHAR(50)

)

 

--INSERT THE USERNAMES IN TO THE TABLE VARIABLE

--YOU CAN UNCOMMENT THE BELOW SELECT STATEMENTS TO SEE WHAT IS HAPPENING

INSERT INTO @ColumnNames

SELECT DISTINCT username FROM [dbo].[TimeLogging]

 

SELECT @MaxCount = @@ROWCOUNT--COLLECT MAXIMUM OF USER NAMES COUNT

 

--SELECT @MaxCount

 

--SELECT * FROM @ColumnNames

 

--CREATE A TEMP TABLE WHERE WE ARE GOING TO STORE THE DATA

--INITIALLY CREATE A TABLE WITH ONLY TWO COLUMNS

CREATE TABLE #Temp

(

      ID INT PRIMARY KEY IDENTITY(1,1),

      [Date] VARCHAR(50)

)

 

 

--alter TABLE #Temp add [bubai] decimal(18,2)

--NOW WE NEED TO ADD ALL THE USERNAMES AS COLUMNS IN THE #TEMP TABLE

DECLARE @SQL VARCHAR(max)

DECLARE @ColumnName VARCHAR(50)

--LOOP THRU THE USERNAMES

WHILE(@Count <= @MaxCount)

BEGIN

       SET @SQL = ''

       

       --GETTING USERNAMES ONE BY ONE

       SELECT @ColumnName = Columnname FROM @ColumnNames where ID = @Count

       --NOW CREATING A ALTER STATEMENT TO ADD A NEW COLUMN WITH USERNAME

       SET @SQL = 'alter TABLE #Temp add ['+@ColumnName+'] decimal(18,2) default 0'

       Exec(@SQL)--EXECUTE THE ALTER STATEMENT

       SET @Count = @Count+1

END

--SELECT * FROM #Temp--UNCOMMENT THIS TO CHECK THE COLUMNS NOW

 

SET @SQL = ''

DECLARE @ColumnNameslist VARCHAR(max)=''

 

SELECT @ColumnNameslist = '['+ColumnName+']' + ','+@ColumnNameslist  FROM @ColumnNames

SELECT @ColumnNameslist = LEFT(@ColumnNameslist, LEN(@ColumnNameslist) - 1)

--SELECT @ColumnNameslist --NOW WE ARE CREATING COLUMN NAMES LIST

 

DECLARE @AnotherColumnNamesList VARCHAR(max)=''

SELECT @AnotherColumnNamesList = 'ISNULL(['+ColumnName+'],0)' + ','+@AnotherColumnNamesList  FROM @ColumnNames

SELECT @AnotherColumnNamesList = LEFT(@AnotherColumnNamesList, LEN(@AnotherColumnNamesList) - 1)

--SELECT @AnotherColumnNamesList--ANOTHER COLUMN LIST

 

--THESE TWO COLUMN LISTS ARE USED TO BUILD THE PIVOT SQL STATEMENT

--BUILDING THE PIVOT TABLE AND INSERTING DATA INTO TEMP TABLES

SELECT @SQL = 'Insert INTO #Temp ( [Date],'+@ColumnNameslist+')

SELECT [Date],'+@AnotherColumnNamesList+'

FROM

 

(

 

SELECT [Date],[timelogged],[username]

 

FROM [dbo].[TimeLogging]

 

)

as S

 

Pivot

 

(

 

SUM([timelogged])

 

FOR username IN ('+@ColumnNameslist+')

 

)

as P'

--SELECT @SQL

EXEC(@SQL)

--SELECT * FROM #Temp

DECLARE @MaxColumnList VARCHAR(max)=''

SELECT @MaxColumnList = 'Max(['+ColumnName+']) as ' + ColumnName + ','+@MaxColumnList  FROM @ColumnNames

SELECT @MaxColumnList = LEFT(@MaxColumnList, LEN(@MaxColumnList) - 1)

--SELECT @MaxColumnList

 

DECLARE @MaxColumnListGroup VARCHAR(max)=''

SELECT @MaxColumnListGroup = 'Max(['+ColumnName+'])'+ ' + '+@MaxColumnListGroup  FROM @ColumnNames

SELECT @MaxColumnListGroup = LEFT(@MaxColumnListGroup, LEN(@MaxColumnListGroup) - 1)

--SELECT @MaxColumnListGroup

 

DECLARE @SumColumnListGroup VARCHAR(max)=''

SELECT @SumColumnListGroup = 'SUM(['+ColumnName+'])'+ ' , '+@SumColumnListGroup  FROM @ColumnNames

SELECT @SumColumnListGroup = LEFT(@SumColumnListGroup, LEN(@SumColumnListGroup) - 1)

--SELECT @SumColumnListGroup

 

SET @SQL = ''

SELECT @SQL = 'SELECT Convert(nvarchar(30),Cast([Date] as Date),101) as Date,'+@MaxColumnList+',('+@MaxColumnListGroup+') as Total

FROM #Temp

group by Date

union

SELECT '''+'Total'+''', '+@SumColumnListGroup+',SUM('+Replace(@ColumnNameslist,',','+')+') FROM  #Temp'

--SELECT @SQL

EXEC(@SQL)

drop TABLE #Temp

Run the query and the output is as in the following:

Date Ravi Marie Kelly John Joe Total
06/09/2009 0.00 0.00 78.78 0.00 0.00 78.78
10/08/2012 5.50 0.00 0.00 0.00 3.30 8.80
11/08/2012 2.30 0.00 0.00 0.00 7.30 9.60
11/09/2012 0.00 8.30 0.00 0.00 0.00 8.30
12/05/2012 0.00 0.00 0.00 99.90 0.00 99.90
Total 78.78 8.30 78.78 99.90 10.60 205.38

This query dynamically changes with the number of users inserted into the table. You should be able to display the result in the above format with as many users as are inserted into the table.