首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >参数月份选择:查询前一个月、12个月前和过去12个月的平均值。

参数月份选择:查询前一个月、12个月前和过去12个月的平均值。
EN

Stack Overflow用户
提问于 2011-08-03 10:17:25
回答 3查看 2.6K关注 0票数 1

我想玩我的Total_Sales桌子。这就是数据的样子(使用Server 2008 R2)

代码语言:javascript
运行
复制
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查询应该显示如下数据:

代码语言:javascript
运行
复制
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

代码语言:javascript
运行
复制
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年的第一个月,因此本例中没有先前的数据。

我计划使用一个参数,您可以选择一个月。

谢谢你的帮助!

EN

回答 3

Stack Overflow用户

回答已采纳

发布于 2011-08-03 11:11:22

代码语言:javascript
运行
复制
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()函数为您处理这个问题。

此外,我强烈反对使用年份和月份字段。相反,我建议使用DATETIME字段来表示“月开始”,并使用Server的日期函数.

代码语言:javascript
运行
复制
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
EN

Stack Overflow用户

发布于 2011-08-03 11:36:44

我不知道的另一个答案是更快还是更不.

代码语言:javascript
运行
复制
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
票数 0
EN

Stack Overflow用户

发布于 2011-08-05 15:36:50

来自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(如果/当真正的数据到达时,更新)。但如果你不能..。

代码语言:javascript
运行
复制
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.>
票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/6924914

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档