我想玩我的 Total_Sales 表格。 这就是数据的样子(使用SQL Server 2008 R2)
Name Year Month Sales
------ ---- ----- -----
Alfred 2011 1 100
Alfred 2011 2 200
Alfred 2011 3 300
Alfred 2011 4 400
Alfred 2011 5 500
Alfred 2011 6 600
Alfred 2011 7 700
Alfred 2011 8 800
Alfred 2011 9 900
Alfred 2011 10 500
Alfred 2011 11 500
Alfred 2011 12 500
我想要创建的SQL查询应该显示如下数据:
Name Year Month Sales Prev_Month Month_Last_Year_Sales Last_12_Month_AVG
------ ---- ----- ----- ---------- --------------------- -----------------
Alfred 2011 1 100 NULL (year 2010, month 1) (2010_01 to 2011_01)/(12)
Alfred 2011 2 200 100 (year 2010, month 2) (2010_02 to 2011_02)/(12)
Alfred 2011 3 300 200 (year 2010, month 3) (2010_03 to 2011_03)/(12)
Alfred 2011 4 400 300 (year 2010, month 4) (2010_04 to 2011_04)/(12)
Alfred 2011 5 500 400 (year 2010, month 5) (2010_05 to 2011_05)/(12)
Alfred 2011 6 600 500 (year 2010, month 6) (2010_06 to 2011_06)/(12)
Alfred 2011 7 700 600 (year 2010, month 7) (2010_07 to 2011_07)/(12)
Alfred 2011 8 800 700 (year 2010, month 8) (2010_08 to 2011_08)/(12)
Alfred 2011 9 900 800 (year 2010, month 9) (2010_09 to 2011_09)/(12)
Alfred 2011 10 500 900 (year 2010, month 10) (2010_10 to 2011_10)/(12)
Alfred 2011 11 500 500 (year 2010, month 11) (2010_11 to 2011_11)/(12)
Alfred 2011 12 500 500 (year 2010, month 12) (2010_12 to 2011_12)/(12)
要复制上个月我使用的是:Copy prior month value and insert into new row
SELECT
TS.name,
TS.year,
TS.month,
TS.sales,
COALESCE(TS2.sales, 0) AS prior_month_sales
FROM
TotalSales TS
LEFT OUTER JOIN TotalSales TS2 ON
TS2.name = TS.name AND
(
(TS2.year = TS.year AND TS2.month = TS.month - 1) OR
(TS.month = 1 AND TS2.month = 12 AND TS2.year = TS.year - 1)
)
Prev_Month中的NULL表示Total_Sales的开头是2011年第1个月,因此此示例没有先前的数据。
我打算使用一个参数,您可以选择一个月。
谢谢你的帮助!
答案 0 :(得分:1)
SELECT
[this_month].*,
[last_month].Sales AS [prev_month_sales],
[last_year].Sales AS [month_last_year_sales],
[yearly].AverageSales AS [last_12_month_average]
FROM
Total_Sales AS [this_month]
LEFT JOIN
Total_Sales AS [last_month]
ON [last_month].Name = [this_month].Name
AND (
([last_month].Year = [this_month].Year AND [last_month].Month = [this_month].Month - 1)
OR ([last_month].Year = [this_month].Year - 1 AND [last_month].Month = 12 AND [this_month].Month = 1)
)
LEFT JOIN
TotalSales AS [last_year]
ON [last_year].Name = [this_month].Name
AND [last_year].Year = [this_month].Year - 1
AND [last_year].Month = [this_month].Month
CROSS APPLY
(
SELECT
AVG(Sales) AS AverageSales
FROM
Total_Sales
WHERE
Name = [this_month].Name
AND (
(Year = [this_month].Year AND Month <= [this_month].Month)
OR (Year = [this_month].Year - 1 AND Month > [this_month].Month)
)
)
AS [yearly]
平均值不是除以12的值,因为前一年并不总是有12个月的数据。但是AVG()函数会为你解决这个问题。
另外,我非常建议不要使用YEAR和MONTH字段。相反,我建议使用DATETIME字段来表示“月开始”并使用SQL Server的日期函数...
Last Month : MonthStart = DATEADD(MONTH, -1, ThisMonth)
A Year Ago : MonthStart = DATEADD(YEAR, -1, ThisMonth)
Last Year : MonthStart > DATEADD(YEAR, -1, ThisMonth) AND MonthStart <= ThisMonth
答案 1 :(得分:0)
我不知道的另一个答案是更快还是没有...
WITH sales AS (
SELECT
ROW_NUMBER() OVER (PARTITION BY Name ORDER BY Year, Month) AS month_id,
*
FROM
yearly_sales
)
SELECT
Name = [this_month].Name,
Year = MAX([this_month].Year),
Month = MAX([this_month].Month),
Sales = MAX([this_month].Sales),
Last_Month = MAX(CASE WHEN [13_months].month_id = [this_month].month_id - 1 THEN [13_months].Sales END),
Last_Year = MAX(CASE WHEN [13_months].month_id = [this_month].month_id - 12 THEN [13_months].Sales END),
Yearly_AVG = AVG(CASE WHEN [13_months].month_id > [this_month].month_id - 12 THEN [13_months].Sales END)
FROM
Sales AS [this_month]
INNER JOIN
Sales AS [13_months]
ON [13_months].Name = [this_month].Name
AND [13_months].month_id <= [this_month].month_id
AND [13_months].month_id >= [this_month].month_id - 12
GROUP BY
[this_month].Name
答案 2 :(得分:0)
来自AceAlfred -
One problem I have run into, maybe you know a quick fix? When a employee has not booked his sales for a previous month there is no data to display for this individual. Is there a way to add a row with the missing employee, where the "sales" is set to 0 and still pull the data for the other rows? Ex. Year 2012 -- Month 1 -- Name Alfred -- Sales 0 -- Prev 500
一种方法是“修复”您的数据,确保数据始终具有值。我建议在填充数据的任何系统中这样做。或者作为夜间批处理,检查没有输入数据的人并为你添加0(如果/当真实数据到达时更新)。但如果你不能......
CREATE TABLE agent (id INT, name NVARCHAR(128), start_date DATETIME, leave_date DATETIME);
-- populate with your agents
CREATE TABLE calendar (year DATETIME, month DATETIME, day DATETIME);
-- populate with all dates you want to report on
CREATE TABLE sales (agent_id INT, month_start DATETIME, total INT);
-- populate with your data
WITH new_raw_data AS
(
SELECT
agent.id AS [agent_id],
calendar.month AS [month_start],
COALESCE(sales.total, 0) AS [total]
FROM
agent
INNER JOIN
calendar
ON calendar.month_start >= COALESCE(DATEADD(month, -1, agent.start_date), '2000 Jan 01')
AND calendar.month_start <= COALESCE(agent.leave_date, '2079 Dec 31')
LEFT JOIN
sales
ON sales.agent_id = agent.id
AND sales.month_start = calendar.month_start
WHERE
calendar.month_start = calendar.day -- Only use records for the start of each month
)
,
<your other queries, using the nicely cleaned data, go here.>