0

I've tried so hard to understand how to create a pivot table in SQL, but I can't manage it!

I have the following columns:

link_id   route_section   date_1    StartHour     AvJT    data_source
.......   .............  .......   ...........   ......  ............

With 600,000 rows of data.

I need them in the following pivot table;

  • date_1 StartHour as column headings
  • link_id as the row heading
  • AvJT as the data
  • with data_source = '1' as the filter.

PIVOT TABLE

Link_ID 
date_1      StartHour    00001a    000002a    000003a    000004a
20/01/2014    8           456       4657        556       46576
21/01/2014    8           511       4725        601       52154
22/01/2014    8           468       4587        458       47585
23/01/2014    8           456       4657        556       46576
24/01/2014    8           456       4657        556       46576
25/01/2014    8           456       4657        556       46576
26/01/2014    8           456       4657        556       46576

I've managed to get the following code, this works but only gives me date_1 as column heading and not StartHour additionally, or with the filter as date_source = '1'.

    Use [C1_20132014]

DECLARE @DynamicPivotQuery AS NVARCHAR(MAX)
DECLARE @ColumnName AS NVARCHAR(MAX)

--Get distinct values of the PIVOT Column 
SELECT @ColumnName= ISNULL(@ColumnName + ',','') 
       + QUOTENAME(Link_ID)
FROM (SELECT DISTINCT Link_ID FROM C1_May_Routes) AS Link_ID

--Prepare the PIVOT query using the dynamic 
SET @DynamicPivotQuery = 
  N'SELECT Date_1, ' + @ColumnName + '
    FROM C1_May_Routes
    PIVOT(SUM(AvJT) 
          FOR Link_ID IN (' + @ColumnName + ')) AS PVTTable'
--Execute the Dynamic Pivot Query
EXEC sp_executesql @DynamicPivotQuery

Thanks for any help,

Henry

hc91
  • 743
  • 2
  • 6
  • 15

2 Answers2

1

Here you will select the values in a column to show as column in pivot

DECLARE @cols NVARCHAR (MAX)

SELECT @cols = COALESCE (@cols + ',[' + AvJT + ']', '[' + AvJT + ']')
               FROM    (SELECT DISTINCT AvJT FROM YourTable) PV  
               ORDER BY AvJT

Now pivot the query

DECLARE @query NVARCHAR(MAX)
SET @query = 'SELECT * FROM 
             (
                 SELECT date_1, StartHour,AvJT, data_source 
                 FROM YourTable
             ) x
             PIVOT 
             (
                 -- Values in each dynamic column
                 SUM(data_source)
                 FOR AvJT IN (' + @cols + ')                      
            ) p;' 

EXEC SP_EXECUTESQL @query

If you want to do it to where column names are not dynamic, you can do the below query

SELECT DATE_1,STARTHOUR,
MIN(CASE WHEN AvJT='00001a' THEN data_source END) [00001a],
MIN(CASE WHEN AvJT='00002a' THEN data_source END) [00002a],
MIN(CASE WHEN AvJT='00003a' THEN data_source END) [00003a],
MIN(CASE WHEN AvJT='00004a' THEN data_source END) [00004a]
FROM YOURTABLE
GROUP BY  DATE_1,STARTHOUR

EDIT :

I am updating for your updated question.

Declare a variable for filtering data_source

DECLARE @DATASOURCE VARCHAR(20) = '1' 

Instead of QUOTENAME, you can use another format to get the columns for pivot

DECLARE @cols NVARCHAR (MAX)

SELECT @cols = COALESCE (@cols + ',[' + Link_ID + ']', '[' + Link_ID + ']')
               FROM    (SELECT DISTINCT Link_ID FROM C1_May_Routes WHERE data_source=@DATASOURCE) PV  
               ORDER BY Link_ID

Now pivot

DECLARE @query NVARCHAR(MAX)
SET @query = 'SELECT * FROM 
             (
                 -- We will select the data that has to be shown for pivoting
                 -- with filtered data_source
                 SELECT date_1, StartHour,AvJT, Link_ID
                 FROM C1_May_Routes
                 WHERE data_source = '+@DATASOURCE+'
             ) x
             PIVOT 
             (
                 -- Values in each dynamic column
                 SUM(AvJT)
                 -- Select columns from @cols 
                 FOR Link_ID IN (' + @cols + ')                      
            ) p;' 

EXEC SP_EXECUTESQL @query
Sarath Subramanian
  • 20,027
  • 11
  • 82
  • 86
  • Thanks for your answer, I cannot get it to work though! – hc91 Jan 21 '15 at 14:42
  • What happened? What is your problem you are facing? @hc91 – Sarath Subramanian Jan 21 '15 at 14:50
  • I need AvJT to be the data that fills the table. Data_source just needs to be a filter so I can make 4 different tables - source 1, source 2 etc. These should be the variables that go into the table - Date_1 smalldatetime, StartHour smallint, Link_ID VARCHAR(50), AvJT int – hc91 Jan 21 '15 at 14:59
  • Do u mean that u want to filter by date like Date_1 between some dates ?@hc91 – Sarath Subramanian Jan 21 '15 at 15:05
  • Can u provide some sample data to the first table? @hc91 – Sarath Subramanian Jan 21 '15 at 15:19
  • I have updated. Feel free to ask for any changes @hc91 – Sarath Subramanian Jan 22 '15 at 04:00
  • 1
    Thank you so much! That's so helpful. – hc91 Jan 23 '15 at 12:04
  • Is there any way of removing all the columns that do not fulfil the criteria? – hc91 Mar 10 '15 at 13:49
  • I didn't get u. What criteria? @hc91 – Sarath Subramanian Mar 10 '15 at 14:38
  • Well at the moment the WHERE data_source = '+@DATASOURCE+' works well, with only values being displayed for that particular data source. However, the links (across the x axis) remain meaning I need an excel macro to delete them. Also, is there any way to replace 'NULL' with blanks? – hc91 Mar 11 '15 at 15:37
  • See this answer http://stackoverflow.com/questions/28227924/row-and-column-total-in-dynamic-pivot/28233641#28233641 . Here I have used `@NullToZeroCols` variable. You have to change `ISNULL(['+Link_ID+'],0)` to `ISNULL(['+Link_ID+'],'')` and in pivot query, instead of `SELECT * FROM` use `SELECT date_1, StartHour,'+ @NullToZeroCols +' FROM` . @hc91 – Sarath Subramanian Mar 12 '15 at 14:55
0

A crosstab would be something like this. FWIW, I would recommend using better column names than 00001a. Give your column names some meaning so they are easier to work with.

with SortedData as
(
    SELECT date_1
        , StartHour
        , AvJT
        , data_source 
        , ROW_NUMBER() over (partition by date_1 order by AvJT) AS RowNum
    FROM YourTable
)

select date_1
    , StartHour
    , MAX(case when RowNum = 1 then AvJT end) as [00001a]
    , MAX(case when RowNum = 2 then AvJT end) as [00002a]
    , MAX(case when RowNum = 3 then AvJT end) as [00003a]
    , MAX(case when RowNum = 4 then AvJT end) as [00004a]
from SortedData
Sean Lange
  • 33,028
  • 3
  • 25
  • 40
  • Oh, I see, apologies. The column names are link_id's and there are around 6,000 of them. – hc91 Jan 21 '15 at 14:54