SQL Order by the sum of aliases - sql

To preface, this is Microsoft SQL Server. I have several different columns of various earnings from different years. I need to order by the total sales of each given product, but not report it as an actual column. The commented line is how I tried to do it, but it seems you can't order by an alias. How would one go about this?
SELECT
StockItems.StockItemID,
StockItemName,
SUM(CASE WHEN OrderDate >= '2013-01-01'
AND OrderDate < '2014-01-01'
THEN Quantity * OrderLines.UnitPrice END) AS Sales2013,
SUM(CASE WHEN OrderDate >= '2014-01-01'
AND OrderDate < '2015-01-01'
THEN Quantity * OrderLines.UnitPrice END) AS Sales2014,
SUM(CASE WHEN OrderDate >= '2014-01-01'
AND OrderDate < '2015-01-01'
THEN Quantity * OrderLines.UnitPrice END) AS Sales2015,
SUM(CASE WHEN OrderDate >= '2015-01-01'
AND OrderDate < '2016-01-01'
THEN Quantity * OrderLines.UnitPrice END) AS Sales2016
FROM
Warehouse.StockItems
INNER JOIN Sales.OrderLines
ON Warehouse.StockItems.StockItemID = Sales.OrderLines.StockItemID
INNER JOIN Sales.Orders
ON Sales.OrderLines.OrderID = Sales.Orders.OrderID
GROUP BY
StockItems.StockItemID,
StockItemName
--ORDER BY SUM(Sales2013 + Sales2014 + Sales2015 + Sales2016)

Two methods
Put your query as inner query and order on it
put the full formula in order by
query for #1
select * from
(
SELECT
StockItems.StockItemID,
StockItemName,
SUM(CASE WHEN OrderDate >= '2013-01-01'
AND OrderDate < '2014-01-01'
THEN Quantity * OrderLines.UnitPrice END) AS Sales2013,
SUM(CASE WHEN OrderDate >= '2014-01-01'
AND OrderDate < '2015-01-01'
THEN Quantity * OrderLines.UnitPrice END) AS Sales2014,
SUM(CASE WHEN OrderDate >= '2014-01-01'
AND OrderDate < '2015-01-01'
THEN Quantity * OrderLines.UnitPrice END) AS Sales2015,
SUM(CASE WHEN OrderDate >= '2015-01-01'
AND OrderDate < '2016-01-01'
THEN Quantity * OrderLines.UnitPrice END) AS Sales2016
FROM
Warehouse.StockItems
INNER JOIN Sales.OrderLines
ON Warehouse.StockItems.StockItemID = Sales.OrderLines.StockItemID
INNER JOIN Sales.Orders
ON Sales.OrderLines.OrderID = Sales.Orders.OrderID
GROUP BY
StockItems.StockItemID,
StockItemName
) temp
order by SUM(Sales2013 + Sales2014 + Sales2015 + Sales2016)
query for #2
SELECT
StockItems.StockItemID,
StockItemName,
SUM(CASE WHEN OrderDate >= '2013-01-01'
AND OrderDate < '2014-01-01'
THEN Quantity * OrderLines.UnitPrice END) AS Sales2013,
SUM(CASE WHEN OrderDate >= '2014-01-01'
AND OrderDate < '2015-01-01'
THEN Quantity * OrderLines.UnitPrice END) AS Sales2014,
SUM(CASE WHEN OrderDate >= '2014-01-01'
AND OrderDate < '2015-01-01'
THEN Quantity * OrderLines.UnitPrice END) AS Sales2015,
SUM(CASE WHEN OrderDate >= '2015-01-01'
AND OrderDate < '2016-01-01'
THEN Quantity * OrderLines.UnitPrice END) AS Sales2016
FROM
Warehouse.StockItems
INNER JOIN Sales.OrderLines
ON Warehouse.StockItems.StockItemID = Sales.OrderLines.StockItemID
INNER JOIN Sales.Orders
ON Sales.OrderLines.OrderID = Sales.Orders.OrderID
GROUP BY
StockItems.StockItemID,
StockItemName
order by SUM(Quantity * OrderLines.UnitPrice)

SELECT StockItemID
, StockItemName
, Sales2013
, Sales2014
, Sales2015
, Sales2016
, Sales2013 + Sales2014 + Sales2015 + Sales2016 total_sales
FROM
(
SELECT
StockItems.StockItemID,
StockItemName,
SUM(CASE WHEN OrderDate >= '2013-01-01'
AND OrderDate < '2014-01-01'
THEN Quantity * OrderLines.UnitPrice END) AS Sales2013,
SUM(CASE WHEN OrderDate >= '2014-01-01'
AND OrderDate < '2015-01-01'
THEN Quantity * OrderLines.UnitPrice END) AS Sales2014,
SUM(CASE WHEN OrderDate >= '2014-01-01'
AND OrderDate < '2015-01-01'
THEN Quantity * OrderLines.UnitPrice END) AS Sales2015,
SUM(CASE WHEN OrderDate >= '2015-01-01'
AND OrderDate < '2016-01-01'
THEN Quantity * OrderLines.UnitPrice END) AS Sales2016
FROM
Warehouse.StockItems
INNER JOIN Sales.OrderLines
ON Warehouse.StockItems.StockItemID = Sales.OrderLines.StockItemID
INNER JOIN Sales.Orders
ON Sales.OrderLines.OrderID = Sales.Orders.OrderID
GROUP BY
StockItems.StockItemID,
StockItemName
)
ORDER BY total_sales

Add SUM column:
SUM(CASE WHEN OrderDate >= '2013-01-01'
AND OrderDate < '2016-01-01'
THEN Quantity * OrderLines.UnitPrice END) AS Sales_SUM
Then order by Sales_SUM

Well, the best performing solution would require to use a PIVOT, I wrap it in a CTE for better readability:
;WITH pvt AS (
SELECT
StockItems.StockItemID,
StockItemName,
YEAR(OrderDate) AS OrderYear,
Quantity * OrderLines AS SalesTotal,
SUM(Quantity * OrderLines) OVER (PARTITION BY StockItems.StockItemID) AS SalesForStockItemForYear
FROM
Warehouse.StockItems
INNER JOIN Sales.OrderLines
ON Warehouse.StockItems.StockItemID = Sales.OrderLines.StockItemID
INNER JOIN Sales.Orders
ON Sales.OrderLines.OrderID = Sales.Orders.OrderID
WHERE
YEAR(OrderDate) IN (2013,2014,2015,2016)
PIVOT (
SUM(SalesTotal) FOR OrderYear IN ([2013],[2014],[2015],[2016])
)
)
SELECT DISTINCT
pvt.StockItemID,
pvt.StockItemName,
pvt.[2013] as Sales2013,
pvt.[2014] as Sales2014,
pvt.[2015] as Sales2015,
pvt.[2016] as Sales2016
FROM
pvt
ORDER BY
pvt.SalesForStockItemForYear DESC

Related

Needing Help Separating Data into columns

I'm currently using SQL at work to Query a database in order to display certain information. I have each item that's being pulled as separate entities. Whenever I run the Query my results only show under one column. Is there a way to separate this data into separate columns based on alias?
SELECT
count(o.orderid) AS Current_Daily
FROM
orders o
WHERE
o.ship_dt BETWEEN '2020-11-09 00:00:00' AND '2020-11-15 23:59:59'
AND o.orderstatus = 2
UNION
#UNION ALL
SELECT
count(o.orderid) AS Previous_Daily
FROM
orders o
WHERE
o.ship_dt BETWEEN '2019-11-09 00:00:00' AND '2019-11-15 23:59:59'
AND o.orderstatus = 2
UNION
#UNION ALL
SELECT
count(o.orderid) AS Current_Monthly
FROM
orders o
WHERE
o.ship_dt BETWEEN '2020-11-01 00:00:00' AND '2020-11-15 23:59:59'
AND o.orderstatus = 2
UNION
#UNION ALL
SELECT
count(o.orderid) AS Previous_Monthly
FROM
orders o
WHERE
o.ship_dt BETWEEN '2019-11-01 00:00:00' AND '2019-11-15 23:59:59'
AND o.orderstatus = 2
;
Any Help would be greatly appreciated.
Use conditional aggregation, as in:
select
sum(case when ship_dt >= '2020-11-09' and ship_dt < '2020-11-15' then 1 else 0 end) as current_daily,
sum(case when ship_dt >= '2020-11-01' and ship_dt < '2020-11-15' then 1 else 0 end) as current_monthly,
... -- more conditional "sum()"s if needed
from orders o
where orderstatus = 2
You probably just want conditional aggregation. Something like this:
SELECT SUM(CASE WHEN o.ship_dt >= '2020-11-09' AND o.ship_dt < '2020-11-16' THEN 1 ELSE 0 END) AS Current_Daily,
SUM(CASE WHEN o.ship_dt >= '2020-11-01' AND o.ship_dt < '2020-11-16' THEN 1 ELSE 0 END) AS Current_Monthly,
FROM orders o
WHERE o.orderstatus = 2;
You can add additional columns using similar logic.

Speed up Query Run Time with multiple Case When Expressions

I have the following code below. It is a simple Sum with specific conditions and divided by count distinct function with specific conditions. The problem it is taking too long to run. Right now it is 2 Days and it has not finished running. How can I make this faster? This is part of the code the Case whens are repeated over 100 times as I am tracking over every month.
Select
(sum (case when INSTALLATION_TYPE like'%R' and RATE_FAKT = 'VI' and INvoice_Date between '2018-01-01' and '2018-12-31' then QUANT end)/1000)/
Count (Distinct (case when INSTALLATION_TYPE like'%R' and RATE_FAKT = 'VI' and INvoice_Date between '2018-01-01' and '2018-12-31' then MIRN end) )CY18_GJPERMIRN_VI,
(sum (case when RATE_FAKT = 'VB' and INvoice_Date between '2018-01-01' and '2018-12-31' then QUANT end)/1000)/
Count (Distinct (case when INSTALLATION_TYPE like'%R' and RATE_FAKT = 'VB' and INvoice_Date between '2018-01-01' and '2018-12-31' then MIRN end) )CY18_GJPERMIRN_VB,
(sum (case when INSTALLATION_TYPE like'%B' and RATE_FAKT = 'VI' and INvoice_Date between '2018-01-01' and '2018-12-31' then QUANT end)/1000)/
Count (Distinct (case when INSTALLATION_TYPE like'%B' and RATE_FAKT = 'VI' and INvoice_Date between '2018-01-01' and '2019-12-31' then MIRN end) )CY18_GJPERMIRN_VI_Commercial,
(sum (case when INSTALLATION_TYPE like'%R' and RATE_FAKT = 'VI' and INvoice_Date between '2019-01-01' and '2019-08-31' then QUANT end)/1000)/
Count (Distinct (case when INSTALLATION_TYPE like'%R' and RATE_FAKT = 'VI' and INvoice_Date between '2019-01-01' and '2019-08-31' then MIRN end) )CY19_AUG_GJPERMIRN_VI,
(sum (case when RATE_FAKT = 'VB' and INvoice_Date between '2019-01-01' and '2019-08-31' then QUANT end)/1000)/
Count (Distinct (case when INSTALLATION_TYPE like'%R' and RATE_FAKT = 'VB' and INvoice_Date between '2019-01-01' and '2019-08-31' then MIRN end) )CY19_AUG_GJPERMIRN_VB,
(sum (case when INSTALLATION_TYPE like'%B' and RATE_FAKT = 'VI' and INvoice_Date between '2019-01-01' and '2019-08-31' then QUANT end)/1000)/
Count (Distinct (case when INSTALLATION_TYPE like'%B' and RATE_FAKT = 'VI' and INvoice_Date between '2019-01-01' and '2019-08-31' then MIRN end) )CY19_AUG_GJPERMIRN_VI_Commercial
FROM [Analytics_JGN].[dbo].[VW_BILLINGS]
Where MIRN like '524%';
You need to use dynamic PIVOT query to generate columns dynamically. This link will help you in it.
Because I checked that there are 3 columns (GJPERMIRN_VI, GJPERMIRN_VB, GJPERMIRN_VI_Commercial) are repeating year wise and prefix is CY(Last 2 character of year from Invoice date column)_.
I have changed your query from CASE statement to UNION ALL with CTE. This will little bit faster. Please check below query for your answer.
;WITH CTE_GJPERMIRN
AS
(
SELECT
(SUM(ISNULL(QUANT,0)) / 1000) / ISNULL(COUNT(DISTINCT MIRN),1) AS CY18_GJPERMIRN_VI,
0 AS CY18_GJPERMIRN_VB,
0 AS CY18_GJPERMIRN_VI_Commercial,
0 AS CY19_AUG_GJPERMIRN_VI,
0 AS CY19_AUG_GJPERMIRN_VB,
0 AS CY19_AUG_GJPERMIRN_VI_Commercial
FROM [Analytics_JGN].[dbo].[VW_BILLINGS]
Where MIRN LIKE '524%'
AND INSTALLATION_TYPE LIKE '%R'
AND RATE_FAKT = 'VI'
AND INvoice_Date BETWEEN '2018-01-01' AND '2018-12-31'
UNION ALL
SELECT
0 AS CY18_GJPERMIRN_VI,
(SUM(ISNULL(QUANT,0)) / 1000) / ISNULL(COUNT(DISTINCT MIRN),1) AS CY18_GJPERMIRN_VB,
0 AS CY18_GJPERMIRN_VI_Commercial,
0 AS CY19_AUG_GJPERMIRN_VI,
0 AS CY19_AUG_GJPERMIRN_VB,
0 AS CY19_AUG_GJPERMIRN_VI_Commercial
FROM [Analytics_JGN].[dbo].[VW_BILLINGS]
Where MIRN LIKE '524%'
AND INSTALLATION_TYPE LIKE '%R'
AND RATE_FAKT = 'VB'
AND INvoice_Date BETWEEN '2018-01-01' AND '2018-12-31'
UNION ALL
SELECT
0 AS CY18_GJPERMIRN_VI,
0 AS CY18_GJPERMIRN_VB,
(SUM(ISNULL(QUANT,0)) / 1000) / ISNULL(COUNT(DISTINCT MIRN),1) AS CY18_GJPERMIRN_VI_Commercial,
0 AS CY19_AUG_GJPERMIRN_VI,
0 AS CY19_AUG_GJPERMIRN_VB,
0 AS CY19_AUG_GJPERMIRN_VI_Commercial
FROM [Analytics_JGN].[dbo].[VW_BILLINGS]
Where MIRN LIKE '524%'
AND INSTALLATION_TYPE LIKE '%B'
AND RATE_FAKT = 'VI'
AND INvoice_Date BETWEEN '2018-01-01' AND '2018-12-31' --Consider 2018 year in End Date instead of 2019 in count distinct case statement
UNION ALL
SELECT
0 AS CY18_GJPERMIRN_VI,
0 AS CY18_GJPERMIRN_VB,
0 AS CY18_GJPERMIRN_VI_Commercial,
(SUM(ISNULL(QUANT,0)) / 1000) / ISNULL(COUNT(DISTINCT MIRN),1) AS CY19_AUG_GJPERMIRN_VI,
0 AS CY19_AUG_GJPERMIRN_VB,
0 AS CY19_AUG_GJPERMIRN_VI_Commercial
FROM [Analytics_JGN].[dbo].[VW_BILLINGS]
Where MIRN LIKE '524%'
AND INSTALLATION_TYPE LIKE'%R'
AND RATE_FAKT = 'VI'
AND INvoice_Date BETWEEN '2019-01-01' AND '2019-08-31'
UNION ALL
SELECT
0 AS CY18_GJPERMIRN_VI,
0 AS CY18_GJPERMIRN_VB,
0 AS CY18_GJPERMIRN_VI_Commercial,
0 AS CY19_AUG_GJPERMIRN_VI,
(SUM(ISNULL(QUANT,0)) / 1000) / ISNULL(COUNT(DISTINCT MIRN),1) AS CY19_AUG_GJPERMIRN_VB,
0 AS CY19_AUG_GJPERMIRN_VI_Commercial
FROM [Analytics_JGN].[dbo].[VW_BILLINGS]
Where MIRN LIKE '524%'
AND INSTALLATION_TYPE LIKE '%R'
AND RATE_FAKT = 'VB'
AND INvoice_Date BETWEEN '2019-01-01' AND '2019-08-31'
UNION ALL
SELECT
0 AS CY18_GJPERMIRN_VI,
0 AS CY18_GJPERMIRN_VB,
0 AS CY18_GJPERMIRN_VI_Commercial,
0 AS CY19_AUG_GJPERMIRN_VI,
0 AS CY19_AUG_GJPERMIRN_VB,
(SUM(ISNULL(QUANT,0)) / 1000) / ISNULL(COUNT(DISTINCT MIRN),1) AS CY19_AUG_GJPERMIRN_VI_Commercial
FROM [Analytics_JGN].[dbo].[VW_BILLINGS]
Where MIRN LIKE '524%'
AND INSTALLATION_TYPE LIKE '%B'
AND RATE_FAKT = 'VI'
AND INvoice_Date BETWEEN '2019-01-01' AND '2019-08-31'
)
SELECT
SUM(CG.CY18_GJPERMIRN_VI) AS CY18_GJPERMIRN_VI,
SUM(CG.CY18_GJPERMIRN_VB) AS CY18_GJPERMIRN_VB,
SUM(CG.CY18_GJPERMIRN_VI_Commercial) AS CY18_GJPERMIRN_VI_Commercial,
SUM(CG.CY19_AUG_GJPERMIRN_VI) AS CY19_AUG_GJPERMIRN_VI,
SUM(CG.CY19_AUG_GJPERMIRN_VB) AS CY19_AUG_GJPERMIRN_VB,
SUM(CG.CY19_AUG_GJPERMIRN_VI_Commercial) AS CY19_AUG_GJPERMIRN_VI_Commercial
FROM CTE_GJPERMIRN CG
Note: CY18_GJPERMIRN_VI_Commercial - You may put wrong end date in COUNT(DISTINCT) Invoice date case statement, which I have corrected.
For performance troubleshooting you can try using many separate select statements instead of many case statements in 1 select statement. Something like: (untested)
select *
from (
Select sum(isnull(QUANT,0)/1000/Count(Distinct MIRN) CY18_GJPERMIRN_VI
FROM [Analytics_JGN].[dbo].[VW_BILLINGS]
Where MIRN like '524%'
and INSTALLATION_TYPE like'%R'
and RATE_FAKT = 'VI'
and INvoice_Date between '2018-01-01' and '2018-12-31'
) a
full outer join
(
select sum(isnull(QUANT,0)/1000/Count(Distinct(MIRN) CY18_GJPERMIRN_VB
FROM [Analytics_JGN].[dbo].[VW_BILLINGS]
Where MIRN like '524%'
and RATE_FAKT = 'VB'
and INvoice_Date between '2018-01-01' and '2018-12-31'
) b on 1=1
Or another approach is to use group by instead of case statements -- presuming it is reasonable. The date ranges would still need to be case statements, but RATE_FAKT and INSTALLATION_TYPE could most likely be moved to GROUP BY.
Your query can be optimized in 2-4 steps because of communication problem.1. First you load the require data in Temp table.2. Since you are saying that this is only part of code so consider my script to incomplete as well.
CREATE TABLE #temp
(
INSTALLATION_TYPE VARCHAR(1),
RATE_FAKT VARCHAR(2) ,
INvoice_Date DATETIME,
QUANT INT,
MIRN INT
)
INSERT INTO #temp
(
INSTALLATION_TYPE,
RATE_FAKT,
INvoice_Date,
QUANT,
MIRN
)
SELECT
RIGHT(INSTALLATION_TYPE,1),
RATE_FAKT,
INvoice_Date,
QUANT,
MIRN
FROM [Analytics_JGN].[dbo].[VW_BILLINGS]
WHERE INvoice_Date >= '2018-01-01'
AND INvoice_Date <= '2019-12-31'
SELECT * FROM #temp
DROP TABLE #temp;

Using DB2 column alias within same select

I have a working query but I'm trying to use the column aliases in order to create more calculations in my select and it says the column can't be found (i.e. it can't use the alias).
For instance, the working query:
select employee,
sum(case when date_field between '2018-01-01' and '2018-01-31' and category = 'CategoryOne' then salesprice else 0 end) as priorDate,
sum(case when date_field between '2018-01-01' and '2018-01-31' then salesprice else 0 end) as priorTotal,
cast(Round((DEC(sum(case when date_field between '2018-01-01' and '2018-01-31' and category = 'CategoryOne' then salesprice else 0 end),12,2)/sum(case when date_field between '2018-01-01' and '2018-01-31' then salesprice else 0 end)) * 100,2) as decimal(12,2)) as priorPercent,
sum(case when date_field between '2019-01-01' and '2019-01-31' and category = 'CategoryOne' then salesprice else 0 end) as currentDate,
sum(case when date_field between '2019-01-01' and '2019-01-31' then salesprice else 0 end) as currentSales,
cast(Round((DEC(sum(case when date_field between '2019-01-01' and '2019-01-31' and category = 'CategoryOne' then salesprice else 0 end),12,2)/sum(case when date_field between '2019-01-01' and '2019-01-31' then salesprice else 0 end)) * 100,2) as decimal(12,2)) as currentPercent
from table
group by employee;
But for my two percentages (the two rows that start with cast) I've tried using just priorDate / priorTotal but it won't work and so I have to repeat the 2 whole calculations as a percentage.
I want to also obtain a difference in percentages which would be much easier to declare by using the aliases, and maybe more performant?
You can write this using a CTE/subquery:
with t as (
select employee,
sum(case when date_field between '2018-01-01' and '2018-01-31' and category = 'CategoryOne' then salesprice else 0 end) as priorDate,
sum(case when date_field between '2018-01-01' and '2018-01-31' then salesprice else 0 end) as priorTotal,
sum(case when date_field between '2019-01-01' and '2019-01-31' and category = 'CategoryOne' then salesprice else 0 end) as currentDate,
sum(case when date_field between '2019-01-01' and '2019-01-31' then salesprice else 0 end) as currentSales,
from table
group by employee
)
select t.*,
round(t.priorDate * 100.0 / nullif(t.priorTotal, 0), 2) as priorPercent,
round(t.priorTotal * 100.0 / nullif(t.currentTotal, 0), 2) as currentPercent
from t;

Calculate MTD using CTE and Projected Sales in SQL

I am trying to add MTD Sales in a SQL Query. I figured out how to do that with JOINS but i want to use a CTE to calculate MTD sales and then use that to calculate projected_sales.Formula for projected sales is (MTD/wkdaysinmonth*wkdaystodate)[which is also stored in CTE Table). Is there a way to make it easy? I wrote the following code;
Input:
Email PaymentAmount orderdate
xyz#gmail.com 10 11/01/2018
xyz#gmail.com 20 11/09/2018
sample output:
EmailAddress MTD Projected_sales
xyz#gmail.com 30 0.19
where Projected sales is calculated as number of days passed=7 and total number of business days in november 22. {[30/7*22]=0.19} (Present date = 11/09/2018)
with dates as(
select dateadd(d,-day(getdate())+1,convert(date,getdate())) as startofmonth,
dateadd(d,-1,dateadd(m,1,dateadd(d,-day(getdate())+1,convert(date,getdate())))) as endofmonth,
convert(date,getdate()) as today
)
,daycounts as(
select dates.*,
(DATEDIFF(dd, startofmonth, endofmonth) + 1)
-(DATEDIFF(wk, startofmonth, endofmonth) * 2)
-(CASE WHEN DATENAME(dw, startofmonth) = 'Sunday' THEN 1 ELSE 0 END)
-(CASE WHEN DATENAME(dw, endofmonth) = 'Saturday' THEN 1 ELSE 0 END) as wkdaysinmonth,
(DATEDIFF(dd, startofmonth, today) + 1)
-(DATEDIFF(wk, startofmonth, today) * 2)
-(CASE WHEN DATENAME(dw, startofmonth) = 'Sunday' THEN 1 ELSE 0 END)
-(CASE WHEN DATENAME(dw, today) = 'Saturday' THEN 1 ELSE 0 END) as wkdaystodate
from dates
)
SELECT DISTINCT Customers.EmailAddress as email,
o1.YTD
FROM
Customers
INNER JOIN
Orders
ON
Orders.CustomerID= Customers.CustomerID
JOIN
(SELECT
c.EmailAddress,
SUM(Orders.PaymentAmount) AS YTD
FROM
Customers c
JOIN
Orders
ON c.CustomerID=Orders.CustomerID
WHERE
Orders.OrderDate BETWEEN '01/01/2018 00:00' AND GETDATE()
GROUP BY
EmailAddress) AS o1 ON o1.EmailAddress = Customers.EmailAddress
WHERE
Orders.OrderDate >= (GETDATE()-7)
You can try to use cte recursive create a calendar table for orderdate startDate to endDate.
Then OUTER JOIN base on calendar table and do condition aggregate function in subquery get workdate.
;WITH cte
AS (SELECT email,
Dateadd(day, 1, Eomonth(Min(orderdate), -1)) minDt,
Dateadd(day, 1, Eomonth(Max(orderdate))) maxDt
FROM t
GROUP BY email
UNION ALL
SELECT email,
Dateadd(day, 1, mindt),
maxdt
FROM cte
WHERE Dateadd(day, 1, mindt) < maxdt),
cte2
AS (SELECT *,
Count(CASE
WHEN Datename(dw, t1.mindt) NOT IN ('Sunday', 'Saturday' )
THEN
1
END) OVER( ORDER BY t1.mindt) workdt
FROM cte t1)
SELECT t1.email,
t2.total,
Max(diffdt) / ( Max(workdt) * Max(workdtmax) * 1.0 ) Projected_sales
FROM (SELECT *,
Max(workdt)
OVER(
partition BY email
ORDER BY workdt DESC) workdtMax,
Datediff(day, Min(mindt) OVER(partition BY email ORDER BY workdt)
, Max(mindt) OVER(partition BY email ORDER BY workdt DESC)) + 1 diffdt
FROM cte2) t1
LEFT JOIN (SELECT email,
Sum(paymentamount) total,
Min(orderdate) minDt,
Max(orderdate) maxDt
FROM t
GROUP BY email) t2
ON t1.mindt BETWEEN t2.mindt AND t2.maxdt
AND t1.email = t2.email
WHERE t2.total IS NOT NULL
GROUP BY t1.email,
t2.total
sqlfiddle
Reuslt
email total Projected_sales
xyz#gmail.com 30 0.19480519480519
You can generate a "calendar" table that has the weekdays for each day in the month.
Your calculation for the projected doesn't make sense to me. So, I've also included what I consider to be a better calculation:
with dates as (
select distinct dte,
(case when datename(weekday, dte) not in ('Saturday', 'Sunday') then 1 else 0 end) as num_weekdays,
dte as month_start
from t cross apply
(values (dateadd(day, 1 - day(orderdate), orderdate))) v(dte)
union all
select dateadd(day, 1, d.dte),
(case when datename(weekday, dte) not in ('Saturday', 'Sunday') then 1 else 0 end) + num_weekdays,
d.month_start
from dates d
where dte < dateadd(day, -1, dateadd(month, 1, month_start))
),
d as (
select d.*, max(num_weekdays) over (partition by month_start) as month_weekdays
from dates d
)
select d.month_start, t.email,
sum(paymentamount) as mtd,
sum(paymentamount) * max(month_weekdays) / max(d.num_weekdays) as my_projected,
sum(paymentamount) * 1.0 / (max(month_weekdays) * max(d.num_weekdays)) as your_projected
from t join
d
on t.orderdate = d.orderdate
group by d.month_start, t.email;
Here is a db<>fiddle.

SubQuery accessing parent value

Hello all I am having a issue with this:
Select Customer_Tool_Lookup.ID,
Customer.CustomerName,
(select count(ID) as perDay
FROM CustomerData
WHERE DatetimeInserted >= '2013-04-29 00:00:00.000'
AND DatetimeInserted <= '2013-04-29 11:59:59.599'
AND Customer_ID = Customer_Tool_Lookup.Customer_ID) as DCount,
(select count(ID) as perMonth
FROM CustomerData
WHERE DatetimeInserted >= '2013-04-01 00:00:00.000'
AND DatetimeInserted <= '2013-04-30 11:59:59.599'
AND Customer_ID = Customer_Tool_Lookup.Customer_ID) as mCount,
(select count(ID) as perYear
FROM CustomerData
WHERE DatetimeInserted >= '2013-01-01 00:00:00.000'
AND DatetimeInserted <= '2013-04-30 11:59:59.599'
AND Customer_ID = Customer_Tool_Lookup.Customer_ID) as yCount,
Customer_tool_Lookup.PricePerClick,
Customer_Tool_lookup.MinimumPerMonth,
case
when ClicksPerMonth > (select count(ID) as perMonth
FROM CustomerData
WHERE DatetimeInserted >= '2013-04-01 00:00:00.000'
AND DatetimeInserted <= '2013-04-30 11:59:59.599'
AND Customer_ID = Customer_Tool_Lookup.Customer_ID)
then ClicksPerMonth
else ((select count(ID) as perMonth
FROM CustomerData
WHERE DatetimeInserted >= '2013-04-01 00:00:00.000'
AND DatetimeInserted <= '2013-04-30 11:59:59.599'
AND Customer_ID = Customer_Tool_Lookup.Customer_ID) - Customer_tool_lookup.MinimumPerMonth) * PricePerClick END as TDMonth
FROM Customer_tool_Lookup Left join Customer on Customer.ID = Customer_Tool_Lookup.Customer_ID
I am getting an error:
Invalid objectName 'Customer_tool_Lookup'
It started when I added the and statement at the end of the subquery:
AND Customer_ID = Customer_Tool_Lookup.Customer_ID <--
one each of them.
I normally don't ask SQL questions I have done subqueries before but for some reason I have trouble using parent data.
Thanks!
My suggestion would be to convert those correlated subqueries into a single subquery that you join to. If you use this subquery, then you can access the alias inside of your TDMonth CASE expression:
Select ctl.ID,
c.CustomerName,
cd.DCount,
cd.mCount,
cd.yCount
ctl.PricePerClick,
ctl.MinimumPerMonth,
case
when ClicksPerMonth > cd.mCount
then ClicksPerMonth
else (cd.mCount - ctl.MinimumPerMonth) * PricePerClick
END as TDMonth
from Customer_tool_Lookup ctl
left join Customer c
on c.ID = ctl.Customer_ID
left join
(
select Customer_ID,
COUNT(case
when DatetimeInserted >= '2013-04-29 00:00:00.000'
and DatetimeInserted <= '2013-04-29 11:59:59.599'
then ID end) as DCount,
COUNT(case
when DatetimeInserted >= '2013-04-01 00:00:00.000'
and DatetimeInserted <= '2013-04-30 11:59:59.599'
then ID end) as mCount,
COUNT(case
when DatetimeInserted >= '2013-01-01 00:00:00.000'
and DatetimeInserted <= '2013-04-30 11:59:59.599'
then ID end) as yCount
from CustomerData
group by Customer_ID
) cd
on ctl.Customer_ID = cd.Customer_ID