SQL query two PIVOT columns combine - sql

select pvtMonth.CardName, [1] as [Jan Sales], [2] as [Feb Sales], [3] as [Mar Sales], [4] as [Apr Sales], [5] as [May Sales],
[6] as [Jun Sales], [7] as [Jul Sales], [8] as [Aug Sales], [9] as [Sep Sales], [10] as [Oct Sales], [11] as [Nov Sales], [12] as [Dec Sales] from
(
select X.CardName, SUM(X.[Total Sales S$]) as [Sales $] , X.Month from Data X group by X.CardName ,X.Month
) X PIVOT
(
sum(X.[Sales $])
FOR [Month]
IN ( [1], [2], [3], [4], [5], [6], [7], [8], [9], [10], [11], [12] )
) AS pvtMonth order by pvtMonth.CardName asc
now i need add one more called "Jan Gp" the column name is "X.Gp". How to update my query. I need the result set like below

I would recommend using conditional aggregation instead of the pivot syntax. It is much more flexible (and at least as efficient). You seem to want something like:
select
cardName,
sum(case when month = 1 then [Total Sales S$] end) [Jan Sales $],
sum(case when month = 1 then [Total Sales SGP] end) [Jan Sales GP],
sum(case when month = 2 then [Total Sales S$] end) [Feb Sales $],
sum(case when month = 2 then [Total Sales SGP] end) [Feb Sales GP],
...
from data
group by cardName

Related

Incorrect 4th & 1st Quarter Sales Values in query

I've been writing a query to group sales by year with other columns containing quarterly sales, growth per quarter in percentage, quarter on quarter change in quarterly sales and total annual sales in the last column from the .
I have ran the following query:
WITH Sales_By_Quarter AS
(
SELECT
DATEPART(YEAR, OrderDate) AS [Year],
DATEPART(QUARTER, OrderDate) AS [Quarter],
SUM(TotalDue) AS [Quarterly Sales],
SUM(TotalDue) - LAG(SUM(TotalDue)) OVER (PARTITION BY DATEPART(YEAR, OrderDate) ORDER BY DATEPART(QUARTER, OrderDate)) AS [Change]
FROM Sales.SalesOrderHeader
GROUP BY DATEPART(YEAR, OrderDate), DATEPART(QUARTER, OrderDate)
),
Annual_Sales AS
(
SELECT
[Year],
SUM([Quarterly Sales]) AS [Total Annual Sales],
SUM([Quarterly Sales]) - LAG(SUM([Quarterly Sales])) OVER (ORDER BY [Year]) AS [Annual Growth]
FROM Sales_By_Quarter
GROUP BY [Year]
)
-- SELECT * FROM Annual_Sales;
SELECT
Sales_By_Quarter.[Year],
SUM(CASE WHEN Sales_By_Quarter.[Quarter] = 1 THEN Sales_By_Quarter.[Quarterly Sales] END) AS [Q1],
SUM(CASE WHEN Sales_By_Quarter.[Quarter] = 1 THEN (Sales_By_Quarter.[Quarterly Sales]/Annual_Sales.[Total Annual Sales]*100) END) as [Annual %],
SUM(CASE WHEN Sales_By_Quarter.[Quarter] = 1 THEN Sales_By_Quarter.[Quarterly Sales] END) AS [4 to 1],
SUM(CASE WHEN Sales_By_Quarter.[Quarter] = 2 THEN Sales_By_Quarter.[Quarterly Sales] END) AS [Q2],
SUM(CASE WHEN Sales_By_Quarter.[Quarter] = 2 THEN Sales_By_Quarter.[Quarterly Sales]/Annual_Sales.[Total Annual Sales]*100 END) as [Annual %],
SUM(CASE WHEN Sales_By_Quarter.[Quarter] = 2 THEN Sales_By_Quarter.[Change] END) AS [1 to 2],
SUM(CASE WHEN Sales_By_Quarter.[Quarter] = 3 THEN Sales_By_Quarter.[Quarterly Sales] END) AS [Q3],
SUM(CASE WHEN Sales_By_Quarter.[Quarter] = 3 THEN Sales_By_Quarter.[Quarterly Sales]/Annual_Sales.[Total Annual Sales]*100 END) as [Annual %],
SUM(CASE WHEN Sales_By_Quarter.[Quarter] = 3 THEN Sales_By_Quarter.[Change] END) AS [2 to 3],
SUM(CASE WHEN Sales_By_Quarter.[Quarter] = 4 THEN Sales_By_Quarter.[Quarterly Sales] END) AS [Q4],
SUM(CASE WHEN Sales_By_Quarter.[Quarter] = 4 THEN Sales_By_Quarter.[Quarterly Sales]/Annual_Sales.[Total Annual Sales]*100 END) as [Annual %],
SUM(CASE WHEN Sales_By_Quarter.[Quarter] = 4 THEN Sales_By_Quarter.[Change] END) AS [3 to 4],
Annual_Sales.[Total Annual Sales]
FROM Sales_By_Quarter
JOIN Annual_Sales ON Sales_By_Quarter.[Year] = Annual_Sales.[Year]
GROUP BY Sales_By_Quarter.[Year], Annual_Sales.[Total Annual Sales], Annual_Sales.[Annual Growth]
ORDER BY Sales_By_Quarter.[Year];
I am getting right values in all columns except the 4 to 1 column. I need some help in fixing this query.
Fixed the definition of Quarterly Change, by not Partitioning on Year, and just Ordering by it instead.
Removed the uneccesary CTE (and the join on it) for yearly figures.
Corrected the column being pivoted for [4 to 1].
Ensured all columns have unique names.
WITH
Sales_By_Quarter AS
(
SELECT
DATEPART(YEAR, OrderDate) AS [Year],
DATEPART(QUARTER, OrderDate) AS [Quarter],
SUM(TotalDue) AS [Quarterly Sales],
SUM(TotalDue) - LAG(SUM(TotalDue)) OVER (ORDER BY DATEPART(YEAR, OrderDate), DATEPART(QUARTER, OrderDate)) AS [Change]
FROM
Sales.SalesOrderHeader
GROUP BY
DATEPART(YEAR, OrderDate),
DATEPART(QUARTER, OrderDate)
)
SELECT
Q.[Year],
SUM(CASE WHEN Q.[Quarter] = 1 THEN Q.[Quarterly Sales] END) AS [Q1],
SUM(CASE WHEN Q.[Quarter] = 1 THEN Q.[Quarterly Sales] END) * 100.0 / SUM(Q.[Quarterly Sales]) AS [Q1 Annual %],
SUM(CASE WHEN Q.[Quarter] = 1 THEN Q.[Change] END) AS [4 to 1],
SUM(CASE WHEN Q.[Quarter] = 2 THEN Q.[Quarterly Sales] END) AS [Q1],
SUM(CASE WHEN Q.[Quarter] = 2 THEN Q.[Quarterly Sales] END) * 100.0 / SUM(Q.[Quarterly Sales]) AS [Q2 Annual %],
SUM(CASE WHEN Q.[Quarter] = 2 THEN Q.[Change] END) AS [1 to 2],
SUM(CASE WHEN Q.[Quarter] = 3 THEN Q.[Quarterly Sales] END) AS [Q3],
SUM(CASE WHEN Q.[Quarter] = 3 THEN Q.[Quarterly Sales] END) * 100.0 / SUM(Q.[Quarterly Sales]) AS [Q3 Annual %],
SUM(CASE WHEN Q.[Quarter] = 3 THEN Q.[Change] END) AS [2 to 3],
SUM(CASE WHEN Q.[Quarter] = 4 THEN Q.[Quarterly Sales] END) AS [Q4],
SUM(CASE WHEN Q.[Quarter] = 4 THEN Q.[Quarterly Sales] END) * 100.0 / SUM(Q.[Quarterly Sales]) AS [Q4 Annual %],
SUM(CASE WHEN Q.[Quarter] = 4 THEN Q.[Change] END) AS [3 to 4],
SUM(Q.[Quarterly Sales]) AS [Total Annual Sales],
SUM(Q.[Quarterly Sales]) - LAG(SUM(Q.[Quarterly Sales])) OVER (ORDER BY Q.[Year]) AS [Annual Growth]
FROM
Sales_By_Quarter As Q
GROUP BY
Q.[Year]
ORDER BY
Q.[Year]

Is it possible to build this table using SQL?

I have 2 tables, a Sales table and a Payment table structured like the below.
The 2 are joined using the ContractID column. What I want to see is a matrix that shows me at the top, the sum of (sold amount) per monthyear. Then on the left, I want to see the payment dates by month year, and any payments that have been made. My ideal output would look like the below.
The yellow line being the total sold by month-year, and the green lines being all the payments that have been made from the payments table. I don't really know where to start with this one, does anyone have any advice on how to achieve this? I am going to unpivot the sold table first to get my dates across the top, just pondering the next step to pull this table together?
If I didn't understand wrong, it should be like this.
WITH PaymentMatrix
AS
(
SELECT
PaymentMonth,
SoldAmount,
[1] AS Jan,
[2] AS Feb,
[3] AS Mrz,
[4] AS Apr,
[5] AS Mai,
[6] AS Jun,
[7] AS Jul,
[8] AS Aug,
[9] AS Sep,
[10] AS Okt,
[11] AS Nov,
[12] AS Dez
FROM
(
Select
MONTH(S.SoldDate) as SoldMonth,
MONTH(P.PaymentDate) as PaymentMonth,
SUM(S.SoldAmount) as SoldAmount,
SUM(P.PaymentAmount) as PaymentAmount
from Sales S
INNER JOIN Payment P ON S.ContractID = P.ContractID
GROUP BY
MONTH(S.SoldDate),
MONTH(P.PaymentDate)
) source
PIVOT
(
SUM(PaymentAmount)
FOR SoldMonth
IN ( [1], [2], [3], [4], [5], [6], [7], [8], [9], [10], [11], [12] )
) AS pvtMonth
)
SELECT
PaymentMonth,
SUM(SoldAmount) AS Sold,
sum(Jan)as Jan , sum(Feb) as Feb, sum(Mrz) as Mrz, sum(Apr) as Apr, sum(Mai) as Mai,
sum(Jun)as Jun , sum(Jul) as Jul, sum(Aug) as Aug, sum(Sep) as Sep, sum(Okt) as Okt,
sum(Nov) as Nov, sum(Dez) as Dez
FROM PaymentMatrix
GROUP BY PaymentMonth
Fidler Sample
Sample Image
I suggest using conditional aggregation and a union.
Since the PIVOT syntax is more limited.
SELECT [Sold], [Jan-22], [Feb-22], [Mar-22]
FROM
(
SELECT 0 as Seq, 'Paid' AS [Sold]
, SUM(CASE WHEN FORMAT([Sold Date],'MMM-yy') = 'Jan-22'
THEN [Sold Amount] ELSE 0 END) AS [Jan-22]
, SUM(CASE WHEN FORMAT([Sold Date],'MMM-yy') = 'Feb-22'
THEN [Sold Amount] ELSE 0 END) AS [Feb-22]
, SUM(CASE WHEN FORMAT([Sold Date],'MMM-yy') = 'Mar-22'
THEN [Sold Amount] ELSE 0 END) AS [Mar-22]
FROM Sales
UNION ALL
SELECT m.Seq, m.PaymentMonth
, SUM(CASE WHEN SoldMonth = 'Jan-22' THEN PaymentAmount ELSE 0 END) AS [Jan-22]
, SUM(CASE WHEN SoldMonth = 'Feb-22' THEN PaymentAmount ELSE 0 END) AS [Feb-22]
, SUM(CASE WHEN SoldMonth = 'Mar-22' THEN PaymentAmount ELSE 0 END) AS [Mar-22]
FROM (VALUES
(1,'Jan-22'),
(2,'Feb-22'),
(3,'Mar-22')
) m(Seq, PaymentMonth)
LEFT JOIN (
SELECT ContractID
, FORMAT(EOMONTH([Payment Date]), 'MMM-yy') AS PaymentMonth
, SUM([Payment Amount]) AS PaymentAmount
FROM Payment
GROUP BY ContractID, EOMONTH([Payment Date])
) p ON p.PaymentMonth = m.PaymentMonth
LEFT JOIN (
SELECT ContractID
, FORMAT(MAX([Sold Date]), 'MMM-yy') AS SoldMonth
, SUM([Sold Amount]) AS SoldAmount
FROM Sales
GROUP BY ContractID
) s ON s.ContractID = p.ContractID
GROUP BY m.Seq, m.PaymentMonth
) q
ORDER BY Seq;
Sold
Jan-22
Feb-22
Mar-22
Paid
2500
100
0
Jan-22
300
0
0
Feb-22
400
50
0
Mar-22
0
0
0
Test on db<>fiddle here

Pivot SQL - Where header includes a DISTINCT and DatePart (data conversion) field

I'm trying to adjust the following output to a pivotted table, but I'm struggling and the Distinct and DatePart (data conversions) are impacting it. (I have to use DatePart, datetrunc() isn't available to me).
ORIGINAL
SELECT DISTINCT (DatePart(Week, S.Date_)) AS Week, T.NAME,SUM([Call Count]) AS TotalCallCount
FROM Sched S LEFT JOIN
SchedTy T
ON S.schedTy_Id = T.id INNER JOIN
Events a
ON a.[Event Id] = s.id
WHERE [Call Count] > 0 AND S.Status_id > 0 AND a.DATE BETWEEN '1/1/2019' AND '1/1/2020'
GROUP BY T.Name, DatePart(Week, S.Date_)
ORIGINAL OUTPUT
Week EventType TotalCallCount
1 Public Holiday 6
3 B 1
3 P 3
3 R 9
4 Rec 12
4 R 3
5 P 3
5 R 15
6 Rec 18
7 P 3
7 Rec 6
7 R 12
8 B 1
8 P 6
8 R 18
9 B 1
9 CDM 3
9 P 6
9 R 15
10 OP 3
DESIRED OUTPUT (EITHER)
Wk1 Wk2 Wk3 Wk4
Public Holiday
R
P
Rec
OR
Public Holiday R P Rec
Wk1
Wk2
Wk3
Wk4
I have tried:
Attempt 1
DECLARE #cols AS NVARCHAR(MAX), #query AS NVARCHAR (MAX) SELECT #cols = STUFF((SELECT ‘,’ + DISTINCT (DatePart(Week, S.Date_))FROM Sched S ORDER By S.Date_ FOR XML PATH(‘’),TYPE).value(‘.’‘NVARCGAR(MAX)’),1,1,’’) Set #query = ‘SELECT T.Name AS EventType,’ + #cols FROM ( SELECT T.Name, S.Date, [Call Count] FROM Sched S LEFT JOIN SchedTy T ON S.schedTy_Id = T.id INNER JOIN Events a ON a.[Event Id] = s.id WHERE [Call Count] > 0 AND S.Status_id > 0 AND a.DATE BETWEEN '1/1/2019'AND '1/1/2020') PIVOT(sum([Call Count]) FOR s.Date_ in ('' + #cols + '')) p Execute(#query)
Attempt 2
SELECT T.Name, [1] AS Wk1, [2] AS Wk2, [3] AS Wk3, [4] AS Wk4, [5] AS Wk5, [6] AS Wk6, [7] AS Wk7, [8] AS Wk8, [9] AS Wk9, [10] AS Wk10, [11] AS Wk11, [12] AS Wk12, [13] AS Wk13, [14] AS Wk14, [15] AS Wk15, [16] AS Wk16, [17] AS Wk17, [18] AS Wk18, [19] AS Wk19, [20] AS Wk20, [21] AS Wk21, [22] AS Wk22, [23] AS Wk23, [24] AS Wk24, [25] AS Wk25, [26] AS Wk26, [27] AS Wk27, [28] AS Wk28, [29] AS Wk29, [30] AS Wk30, [31] AS Wk31, [32] AS Wk32, [33] AS Wk33, [34] AS Wk34, [35] AS Wk35, [36] AS Wk36, [37] AS Wk37, [38] AS Wk38, [39] AS Wk39, [40] AS Wk40, [41] AS Wk41, [42] AS Wk42, [43] AS Wk43, [44] AS Wk44, [45] AS Wk45, [46] AS Wk46, [47] AS Wk47, [48] AS Wk48, [49] AS Wk49, [10] AS Wk50, [51] AS Wk51, [52] AS Wk52 FROM (SELECT DISTINCT (DatePart(Week, S.Date_)) AS Week, T.NAME, ([Call Count]) FROM Sched S LEFT JOIN SchedTy T ON S.schedTy_Id = T.id INNER JOIN Events a ON a.[Event Id] = s.id WHERE [Call Count] > 0 AND S.Status_id > 0 AND a.DATE BETWEEN '1/1/2019' AND '1/1/2020') AS TotalCallCount PIVOT (SUM([Call Count]) FOR(DatePart(Week, S.Date_)) IN [1], [2], [3], [4], [5], [6], [7], [8], [9], [10], [11], [12], [13], [14], [15], [16], [17], [18], [19], [20], [21], [22], [23], [24], [25], [26], [27], [28], [29], [30], [31], [32], [33], [34], [35], [36], [37], [38], [39], [40], [41], [42], [43], [44], [45], [46], [47], [48], [49], [50], [51], [52])AS pvt
I think you can just use conditional aggregation:
SELECT DatePart(Week, S.Date_) AS Week, T.NAME,
SUM(CASE WHEN T.NAME = 'Public Holiday' THEN [Call Count] END) AS total_public_holiday,
SUM(CASE WHEN T.NAME = 'B' THEN [Call Count] END) AS total_b,
SUM(CASE WHEN T.NAME = 'P' THEN [Call Count] END) AS total_p,
SUM(CASE WHEN T.NAME = 'R' THEN [Call Count] END) AS total_r,
SUM(CASE WHEN T.NAME = 'Rec' THEN [Call Count] END) AS total_rec
FROM Sched S LEFT JOIN
SchedTy T
ON S.schedTy_Id = T.id INNER JOIN
Events e
ON e.[Event Id] = s.id
WHERE [Call Count] > 0 AND
S.Status_id > 0 AND
e.DATE >= '2019-01-01' AND
e.DATE < '2020-01-01'
GROUP BY DatePart(Week, S.Date_)

Case Statement Null Issues

I always get null value issues whenever I try to use a case statement on a data from the same column.
Data in database:
Month Sum
Jan 1000
Feb 2000
Mar 3000
Desired Result:
Jan Feb Mar
1000 2000 3000
When I tried using case statement I was running into null issue and was getting results like below:
Jan Feb Mar
1000 Null Null
Null 2000 Null
Null Null 3000
Here is the code that creates null value issue.
select AccountID,
sum(Case when DATEPART(month,EndDateTime) = 10 then Budget End) period1,
sum(case when DATEPART(month,EndDateTime) = 11 then Budget end) period2,
sum(case when DATEPART(month,EndDateTime) = 12 then Budget End) period3,
Description,
from Budget
where DATEPART(month,EndDateTime) in ('10','11','12')
group by AccountID,Description,EndDateTime
order by AccountID,Description,EndDateTime;
Using Pivot function I was able to generate the desired result.
SELECT
AccountID,
[1] AS Jan,
[2] AS Feb,
[3] AS Mar,
[4] AS Apr,
[5] AS May,
[6] AS Jun,
[7] AS Jul,
[8] AS Aug,
[9] AS Sep,
[10] AS Oct,
[11] AS Nov,
[12] AS Dec
FROM
(Select
AccountID,
Budget,
MONTH(EndDateTime) as TMonth
from
dbo.Budget) source
PIVOT
(
SUM(Budget)
FOR TMonth
IN ( [1], [2], [3], [4], [5], [6], [7], [8], [9], [10], [11], [12] )
) AS pvtMonth
The current issue I am now having is that I need to add one more sum function Sum(BudgetNet). Any suggestions?
Thanks.
For the type of result that you are wanting, it looks like you should be using PIVOT instead of CASE.

Year months as Column and Fetch data

I have a table like this in SQL Server 2008
SalesMonth SalesPerson TotalAmount
----------- ----------- -----------
3 Ram 10000
3 Rajesh 25000
4 Rajesh 8500
6 Ram 12000
6 Anand 7000
11 Ram 6500
Results should be .....
SalesPerson Jan Feb Mar Apr Jun Jul Aug Sep Oct Nov Dec
Ram 0 0 10000 0 12000 0 0 0 0 6500 0
Rajesh 0 0 25000 8500 0 0 0 0 0 0 0
Anand 0 0 0 0 7000 0 0 0 0 0 0
Is it possible to get through sql query. If so, please help me...
Try to use PIVOT
SELECT SalesPerson,
ISNULL([1],0) as JAN,
ISNULL([2],0) as FEB,
ISNULL([3],0) as MAR,
ISNULL([4],0) as APR,
ISNULL([5],0) as MAY,
ISNULL([6],0) as JUN,
ISNULL([7],0) as JUL,
ISNULL([8],0) as AUG,
ISNULL([9],0) as SEP,
ISNULL([10],0) as OCT,
ISNULL([11],0) as NOV,
ISNULL([12],0) as DEC
FROM t
PIVOT
( SUM(TotalAmount)
FOR SalesMonth IN
([1],[2],[3],[4],[5],[6],[7],[8],[9],[10],[11],[12])
) AS PivotTable
ORDER BY SalesPerson;
SQLFiddle demo
You will need to use the SQL Server's PIVOT operator:
SELECT SalesPerson, [Jan], [Feb], [Mar], [Apr], [May], [Jun], [Jul], [Aug], [Sep], [Oct], [Nov], [Dec]
FROM (
SELECT MonthName.SalesMonthName, Sales.SalesPerson, Sales.TotalAmount
FROM Sales
INNER JOIN MonthName ON ( MonthName.MonthNumber = Sales.SalesMonth )
) AS SourceTable
PIVOT (
Sum(TotalAmount)
FOR SalesMonthName IN ([Jan], [Feb], [Mar], [Apr], [May], [Jun], [Jul], [Aug], [Sep], [Oct], [Nov], [Dec])
) AS PivotTable
Also, since PIVOT aggregates data, the example above uses the Sum() function. (You could just as easily use Avg(), or a different aggregation function, based upon your needs.)
Your output will be NULL for all elements that do not have values.
NOTE: In the example above, I made an assumption that there is a fictional table (MonthName) that translates month numbers (1, 2,...) to month names (Jan, Feb,...), since your data does not show the 'jump' from month numbers to month names. If you do not want to do this, replace [Jan], [Feb], ..., [Nov], [Dec] with [1], [2], ..., [11], [12] in the SQL statement above (and, of course, remove the INNER JOIN).
SELECT SalesPerson,
[1] as jan, [2] as feb, [3] as mar, [4] as apr, [5] as may, [6] as jun, [7] as jul
, [8] as aug,[9] as sept,[10] as oct,[11] as nov,[12] as decm
FROM
table1
PIVOT
(
sum(TotalAmount)
FOR SalesMonth IN ([1],[2],[3],[4],[5],[6],[7],[8],[9],[10],[11],[12])
) AS PivotTable;