Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

T-SQL - Pivot by week

I'm currently trying to create a T-SQL, which runs through a list of deliveries in a table, and groups them by the Customer and the Depot - so each row will be

Customer, Depot, Total Value (sum of a column called Rate)

However, the customer would like the 'total value' split into the last 9 weeks - so rather than total value, we'll have columns like this:

22/01/2012  29/01/2012  05/02/2012  12/02/2012  19/02/2012  26/02/2012  04/03/2012  11/03/2012  18/03/2012

The dates would of course change for when they run the query - it'll just be the last 9 weeks. They also want a column for the Average of all these.

I understand pivot may help me but I'm a bit stumped on how to do this. Here's my current query:

SELECT d.Name AS 'Depot, s.Name AS 'Customer', SUM(c.Rates) AS 'Total Value'
FROM Deliveries AS c INNER JOIN Account AS s ON c.Customer = s.ID
INNER JOIN Depots AS d ON c.CollectionDepot = d.Letter
GROUP BY d.Name, s.Name

Many thanks!

EDIT: Here's a screenshot of the data currently - we won't need the 'total' column on the end, just there to show you. The 'Date' column is present in the Deliveries table and is called TripDate

enter image description here

like image 962
Chris Avatar asked Dec 14 '25 15:12

Chris


2 Answers

Without knowing your exact data. It hard to predict what you are getting. But I can give you a suggestion of a solution.

Table structure

CREATE TABLE Deliveries
(
    Customer INT,
    CollectionDepot INT,
    Rates FLOAT,
    TripDate DATETIME
)
CREATE TABLE Account
(
    Name VARCHAR(100),
    ID INT
)
CREATE TABLE Depots
(
    Name VARCHAR(100),
    Letter INT
)

Test data

INSERT INTO Deliveries
VALUES
    (1,1,452,GETDATE()-10),
    (1,1,800,GETDATE()-30),
    (1,1,7895,GETDATE()-2),
    (1,1,451,GETDATE()-2),
    (1,1,478,GETDATE()-89),
    (1,1,4512,GETDATE()-31),
    (1,1,782,GETDATE()-20),
    (1,1,652,GETDATE()-5),
    (1,1,752,GETDATE()-452)

INSERT INTO Account
VALUES
    ('Customer 1',1)

INSERT INTO Depots
VALUES
    ('Depot 1',1)

Table that contains the ranges and the formated date

CREATE TABLE #tmp
(
    StartDate DATETIME,
    EndDate DATETIME,
    FomatedDate VARCHAR(20)
)

Calculate the date ranges

;WITH Nbrs ( n ) AS (
        SELECT 0 UNION ALL
        SELECT 1+n FROM Nbrs WHERE n < 8 )
INSERT INTO #tmp
SELECT
    DATEADD(WEEK,-n-1,GETDATE()),
    DATEADD(WEEK,-n,GETDATE()),
    convert(varchar, DATEADD(WEEK,-n,GETDATE()), 112)
FROM
    Nbrs
ORDER BY
    -n

The date columns for the pivot

DECLARE @cols VARCHAR(MAX)
SELECT  @cols = COALESCE(@cols + ','+QUOTENAME(FomatedDate),
                     QUOTENAME(FomatedDate))
FROM 
    #tmp

Declaring some dynamic sql and executing it

DECLARE @query NVARCHAR(4000)=
N'SELECT
    *
FROM
(
    SELECT 
        Depots.Name AS Depot, 
        Account.Name AS Customer, 
        Deliveries.Rates,
        tmp.FomatedDate,
        AVG(Deliveries.Rates) OVER(PARTITION BY 1) AS Average,
        SUM(Deliveries.Rates) OVER(PARTITION BY 1) AS Total
    FROM 
        Deliveries
        JOIN Account 
            ON Deliveries.Customer = Account.ID
        JOIN Depots
            ON Deliveries.CollectionDepot = Depots.Letter
        JOIN #tmp AS tmp
            ON Deliveries.TripDate BETWEEN tmp.StartDate AND tmp.EndDate
) AS p
PIVOT
(
    AVG(rates)
    FOR FomatedDate IN ('+@cols+')
) AS pvt'

EXECUTE(@query)

And then cleaning up after myself.

DROP TABLE Deliveries
DROP TABLE Account
DROP TABLE Depots
DROP TABLE #tmp
like image 104
Arion Avatar answered Dec 16 '25 13:12

Arion


You would have to make use of the PIVOT Keyword which is available in your version of SQL Server. I have outlined how your query should look, of course some tweaking will be required since it is difficult to test without having a copy of your data.

  SELECT Depots.Name AS 'Depot',  Account.Name, '22/01/2012',  '29/01/2012',  '05/02/2012',  '12/02/2012',
   FROM 
(SELECT Name, 
    FROM Deliveries
    INNER JOIN Account ON Deliveries.Customer = Account.ID
    INNER JOIN Depots ON Account.CollectionDepot) AS Source
PIVOT
(
    SUM(Deliveries.Rates)
    FOR Date IN ('22/01/2012',  '29/01/2012',  '05/02/2012',  '12/02/2012')
) AS 'Pivot Table'

For reference you could use this as a guide:

http://msdn.microsoft.com/en-us/library/ms177410.aspx

like image 23
Darren Avatar answered Dec 16 '25 12:12

Darren



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!