我正在尝试在SQL查询中添加MTD Sales。我想出了如何使用JOINS做到这一点,但我想使用CTE来计算MTD销售额,然后使用它来计算projected_sales。预计销售额的公式为(MTD/wkdaysinmonth*wkdaystodate
)[也存储在CTE表中)。有没有办法使它变得容易?我写了以下代码;
输入:
Email PaymentAmount orderdate
xyz@gmail.com 10 11/01/2018
xyz@gmail.com 20 11/09/2018
示例输出:
EmailAddress MTD Projected_sales
xyz@gmail.com 30 0.19
其中,预计销售量是根据天passed=7
和11月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)
答案 0 :(得分:1)
您可以尝试使用cte递归为orderdate
startDate到endDate创建日历表。
然后OUTER JOIN
基于日历表,并在子查询中执行条件聚合功能以获取工作日期。
;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
重新使用
email total Projected_sales
xyz@gmail.com 30 0.19480519480519
答案 1 :(得分:0)
您可以生成一个“日历”表,其中包含一个月中每一天的工作日。
您对预测的计算对我来说没有意义。因此,我还列出了我认为更好的计算方法:
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是db <>小提琴。