Query to "PIVOT" the results of SalesAmount & CumulativeMonthly for specific YEARS - sql

I have a database table that captures every Sales Transaction:
Transactions
(
ID INT,
TransactionDate DATETIME,
SalesAmount MONEY
)
I need to run a T-SQL query to produce a Sales Report, that shows :
(1) Sales (monthly)
(2) Cumulative Monthly Sales
These will be two columns per year; PIVOT the results for next year on next two neighbor columns (structure as ExcelSheet template below). The results will extend horizontally for all Years in the transaction data.

You could use conditional aggegation and window functions, as follows:
select
datename(month, TransactionDate),
sum(case when year(TransactionDate) = 2017 then SalesAmount end) [Sales 2017],
sum(sum(case when year(TransactionDate) = 2017 then SalesAmount end))
over(order by month(TransactionDate)) [Cumulative 2017],
sum(case when year(TransactionDate) = 2018 then SalesAmount end) [Sales 2018],
sum(sum(case when year(TransactionDate) = 2018 then SalesAmount end))
over(order by month(TransactionDate)) [Cumulative 2018],
sum(case when year(TransactionDate) = 2019 then SalesAmount end) [Sales 2019],
sum(sum(case when year(TransactionDate) = 2019 then SalesAmount end))
over(order by month(TransactionDate)) [Cumulative 2019],
from Transactions
group by month(TransactionDate), datename(month, TransactionDate)
order by month(TransactionDate)

Related

Need to get number of Items used in last 3 days as well as used items in last year

I have the query where I can fetch last 3 days records perfectly
Select ProductID, Description, Count(productID) AS [Last 3 days item count]
From VIEW_ItemsUsed
Where DateUsed >= Getdate()-3
Group by ProductID
But when I include the condition for fetching the number of items used in last year in the same query, getting invalid data
Select ProductID, Description, Count(productID) AS [Last 3 days item count], Count(ProductID) AS [Last Year Item counts]
From VIEW_ItemsUsed
Where DateUsed >= Getdate()-3
AND DateUsed >= Getdate()-365
Group by ProductID
Please provide me the solution
I think you just want conditional aggregation:
Select ProductID, Description,
sum(case when dateUsed >= getdate() - 3 then 1 else 0 end) as cnt_3days,
sum(case when dateUsed >= getdate() - 365 then 1 else 0 end) as cnt_365days
From VIEW_ItemsUsed
Where DateUsed >= Getdate() - 365
Group by ProductID, Description;

How to get year numbers in columns

I need to display the number of transactions in individual years for individual employees (ID, 2011, 2012, 2013, 2014) and I should see the number of transactions in every year under years number, but now I receive this form:
How can I change it?
I think I should use WHERE, but I dont know how to do it
My current query is:
SELECT oh.SalesPersonID AS perID,
YEAR(oh.OrderDate) AS [Year], COUNT(*)
FROM Sales.SalesOrderHeader oh
JOIN Person.Person per ON oh.SalesPersonID = per.BusinessEntityID
GROUP BY SalesPersonID, YEAR(OrderDate)
ORDER BY perID, [Year];
Just use conditional aggregation:
SELECT oh.SalesPersonID AS perID,
SUM(CASE WHEN YEAR(oh.OrderDate) = 2011 THEN 1 ELSE 0 END) as cnt_2011,
SUM(CASE WHEN YEAR(oh.OrderDate) = 2012 THEN 1 ELSE 0 END) as cnt_2012,
SUM(CASE WHEN YEAR(oh.OrderDate) = 2013 THEN 1 ELSE 0 END) as cnt_2013,
SUM(CASE WHEN YEAR(oh.OrderDate) = 2014 THEN 1 ELSE 0 END) as cnt_2014
FROM Sales.SalesOrderHeader oh JOIN
Person.Person per
ON oh.SalesPersonID = per.BusinessEntityID
GROUP BY SalesPersonID
ORDER BY perID;

SQL Server allocating values from specified rows to other rows on a condition

I am working with customer-level data for which a large number of rows do not have assigned values in the customer field, but do have values in the sales field. I would like allocate the sales dollars in these rows with "unassigned" customers to rows with customers, and I would like to complete this allocation in proportion to the sales already allocated to named customers. Finally, I would like to delete the rows with unassigned customers from my table. For example, my data looks roughly like:
Year Market Customer Sales
2016 China A 100
2016 China B 150
2016 China Not assigned 200
2015 Europe D 100
In the above example, I would like the sales value in the third record to be allocated to rows 1 and 2 (where year and market are equal to row 3) in proportion to their sales figures. Thus, the final table should look like:
Year Market Customer Sales
2016 China A 180
2016 China B 270
2015 Europe D 100
To start, I've created a new table with each "not assigned" rows, grouped by the relevant dimensions for the allocation.
SELECT *
INTO [dbo].[notassignedtable]
FROM(
SELECT YEAR, Market, Customer, sum(Sales) as Sales
FROM table
WHERE Customer = 'Not assigned'
GROUP BY YEAR, Market, Customer
) grouped
Is this a step in the right direction? Having trouble with where to go from here.
Thanks!
Here is one way
SELECT *
FROM
(SELECT *,
[Sales] + ([Sales] / SUM(
CASE
WHEN [Customer] <> 'Not assigned'
THEN [Sales]
ELSE 0
END) OVER( partition BY [YEAR], Market) * SUM(
CASE
WHEN [Customer] = 'Not assigned'
THEN [Sales]
ELSE 0
END) OVER( partition BY [YEAR], Market)) AS result
FROM Yourtable
) a
WHERE [Customer] <> 'Not assigned'
This is used to find the contribution of each each customer
[Sales] / Sum(CASE WHEN [Customer] <> 'Not assigned' THEN [Sales] ELSE 0 END) OVER( partition BY [Year], Market)
This is used to find the amount that is not assigned
Sum(CASE WHEN [Customer] = 'Not assigned' THEN [Sales] ELSE 0 END) OVER( partition BY [Year], Market))
Multiply the contribution with not asiggned amount
([Sales] / Sum(CASE WHEN [Customer] <> 'Not assigned' THEN [Sales] ELSE 0 END) OVER( partition BY [Year], Market)
* Sum(CASE WHEN [Customer] = 'Not assigned' THEN [Sales] ELSE 0 END) OVER( partition BY [Year], Market))
Then add with original sales to get the result
[Sales] + ([Sales] / Sum(CASE WHEN [Customer] <> 'Not assigned' THEN [Sales] ELSE 0 END) OVER( partition BY [Year], Market)
* Sum(CASE WHEN [Customer] = 'Not assigned' THEN [Sales] ELSE 0 END) OVER( partition BY [Year], Market)) AS result
Live Demo

Oracle monthly totals and grand total column and row

I'm trying to generate a report using Oracle which looks like this:
I got the following tables:
REGION (IDRegion, Region_Name)
SALES (IDSale, Sale_Date, Amount, IDSaleRegion)
Both tables are populated.
I cannot figure out how can I create that report by extracting each sum for the first 3 months and calculate the totals.
I've only made this script but it's not so useful:
SELECT Region_Name as Region,
COALESCE(NULL, NULL) AS "January",
COALESCE(NULL, NULL)AS"February",
COALESCE(NULL, NULL)AS"March",
COALESCE(NULL, NULL)AS"GrandTotal"
FROM REGION r INNER JOIN SALES s ON r.IDRegion=s.IDSaleRegion
GROUP BY Region_Name;
EDIT: Problem solved except the TOTAL (below Region) which calculates the totals from each Month. Any ideas how to add this row?
You can use Conditional Aggregation
select case grouping(Region_Name) when 1 then 'TOTAL' else Region_Name as "Region",
sum(case when extract(month from Sale_Date) = 1 then Amount else 0 end) AS "January",
sum(case when extract(month from Sale_Date) = 2 then Amount else 0 end) AS "February",
sum(case when extract(month from Sale_Date) = 3 then Amount else 0 end) AS "March",
sum(Amount) AS"GrandTotal"
From yourtable
Where extract(month from Sale_Date) <= 3
Group by Rollup (Region_Name);
try something like this:
SELECT Region_Name as Region,
sum(decode(extract(month from Sale_Date), 1, amount)) AS "January",
sum(decode(extract(month from Sale_Date), 2, amount)) AS"February",
sum(decode(extract(month from Sale_Date), 3, amount)) AS"March",
sum(case when extract(month from Sale_Date)<4 then amount end) AS"GrandTotal"
FROM REGION r INNER JOIN SALES s ON r.IDRegion=s.IDSaleRegion
GROUP BY Region_Name;

Aggregation level issue on Teradata/SQL

I am currently learning SQL, as a beginner so apologies if I ask a beginner question. The database I am working on is on of a brand of shopping centers.
I have written a query to retrieve the difference in revenue per store from november to december, which seems OK to me except if I missed something.
Now I would like to adapt it to retrieve which Sku has the biggest the difference of revenue from november to december.
However the query doesn't work, and my results show no data in almost all columns, let alone the calculation column.
Here is my first query (the subquery is there only to clean the data):
SELECT TOP 5 SalesCleaned.Store AS Store, skuinfo.dept AS Dept,
store_msa.city AS City, store_msa.state as State,
SUM(CASE WHEN MonthNb=11 THEN Amount END) AS AmtNov,
SUM(CASE WHEN MonthNb=12 THEN Amount END) AS AmtDec,
SUM(CASE WHEN MonthNb=11 THEN NbOfDates END) AS DNov,
SUM(CASE WHEN MonthNb=12 THEN NbOfDates END) AS DDec,
AmtNov/DNov AS AvgNov, AmtDec/DDec AS AvgDec, (AvgDec-
AvgNov)/AvgNov*100 AS Change
FROM
Skuinfo, store_msa,
(SELECT trnsact.sku as Sku, trnsact.store AS Store, EXTRACT(MONTH from
saledate) as MonthNb, EXTRACT(Year from saledate) AS Yr, SUM(amt) AS
Amount, COUNT(DISTINCT saledate) AS NbOfDates, Amount/NbOfDates AS
AvgPStore, CASE WHEN (Yr=2005 AND MonthNb=8) THEN 'exclude' ELSE
'include' END AS UseDate
FROM trnsact
WHERE(UseDate='include') AND (stype='P')
GROUP BY MonthNb, Store, Yr, stype, Sku
HAVING(NbOfDates>=20)) AS SalesCleaned
WHERE SalesCleaned.store=store_msa.store AND
skuinfo.sku=SalesCleaned.sku
GROUP BY SalesCleaned.Store, City, State, Dept
ORDER BY Change DESC;
And here is the 2nd query, which returns a result wiht a lot of data mmissing, and which I have no idea how to fix:
SELECT SalesCleaned.sku AS Sku,
SUM(CASE WHEN MonthNb=11 THEN Amount END) AS AmtNov,
SUM(CASE WHEN MonthNb=12 THEN Amount END) AS AmtDec,
(AmtDcb - AmtNov)/ AmtDcb *100 AS Change
FROM
(SELECT trnsact.sku AS Sku, trnsact.store AS Store, EXTRACT(MONTH from
saledate) as MonthNb, EXTRACT(Year from saledate) AS Yr, SUM(amt) AS
Amount, COUNT(DISTINCT saledate) AS NbOfDates, Amount/NbOfDates AS
AvgPStore, CASE WHEN (Yr=2005 AND MonthNb=8) THEN 'exclude' ELSE
'include' END AS UseDate
FROM trnsact
WHERE(UseDate='include') AND (stype='P')
GROUP BY Sku, Store, MonthNb, Store, Yr, stype) AS SalesCleaned
GROUP BY Sku, MonthNb, Amount, NbOfDates
HAVING NbOfDates>=20
ORDER BY Change DESC;
Any feedback welcome