【问题标题】:SQL Server - Select Max From "n" Previous MonthsSQL Server - 从前几个月的“n”个中选择最大值
【发布时间】:2019-12-03 14:47:03
【问题描述】:

我正在尝试使用同一个表中某个月份范围内的 MAX 值来更新一个表。我能够从前一个月(上个月)获得 MAX,但无法弄清楚如何一次从多个前几个月获得 MAX。即:前 2 个月的 MAX。

UPDATE t1
SET t1.mymax = t2.mymax
FROM PY t1
INNER JOIN (
    SELECT DATEPART(m, [date]) as [month], DATEPART(yyyy, [date])as [year], MAX([myval]) as mymax
    FROM PY
    GROUP BY DATEPART(m, [date]), DATEPART(yyyy, [date])) AS t2
    ON DATEPART(m, DATEADD(m, -1, t1.[date])) = t2.[month] AND DATEPART(yyyy, DATEADD(m, -1, t1.[date])) = t2.[year]

上面的代码可以获取 myval 的最后几个月的 MAX,但我需要一些可以用过去 2 个月(或其他多个)的 MAX 更新的东西。我认为这不能通过标准 JOIN 完成,但我无法弄清楚接下来的步骤。

以下是工作查询的结果,仅占上个月的一个:

+-----------+---------+-------+
|   Date    |  myval  | mymax |
+-----------+---------+-------+
| 5/1/2019  |   55.51 |       |
| 5/2/2019  |   54.82 |       |
| 5/3/2019  |   54.18 |       |
| 5/6/2019  |   53.56 |       |
| 5/7/2019  |   52.94 |       |
| 5/8/2019  |   53.13 |       |
| 5/9/2019  |   52.23 |       |
| 5/10/2019 |   51.95 |       |
| 5/13/2019 |   51.06 |       |
| 5/14/2019 |   51.38 |       |
| 5/15/2019 |   57.02 |       |
| 5/16/2019 |   54.12 |       |
| 5/17/2019 |   55.52 |       |
| 5/20/2019 | 55.5513 |       |
| 5/21/2019 |   58.13 |       |
| 5/22/2019 |   55.67 |       |
| 5/23/2019 |   53.94 |       |
| 5/24/2019 |   54.06 |       |
| 5/28/2019 |   53.82 |       |
| 5/29/2019 |  52.855 |       |
| 5/30/2019 |  53.335 |       |
| 5/31/2019 |   52.01 |       |
| 6/3/2019  |  51.485 | 58.13 |
| 6/4/2019  |   52.41 | 58.13 |
| 6/5/2019  |   53.75 | 58.13 |
| 6/6/2019  |   54.21 | 58.13 |
| 6/7/2019  |   55.03 | 58.13 |
| 6/10/2019 |   55.96 | 58.13 |
| 6/11/2019 |   56.73 | 58.13 |
| 6/12/2019 |   57.65 | 58.13 |
| 6/13/2019 |   55.78 | 58.13 |
| 6/14/2019 |   54.66 | 58.13 |
| 6/17/2019 |   54.86 | 58.13 |
| 6/18/2019 |   55.75 | 58.13 |
| 6/19/2019 |   55.77 | 58.13 |
| 6/20/2019 |   56.68 | 58.13 |
| 6/21/2019 |   56.98 | 58.13 |
| 6/24/2019 |   56.69 | 58.13 |
| 6/25/2019 |   56.01 | 58.13 |
| 6/26/2019 |   56.36 | 58.13 |
| 6/27/2019 |   55.47 | 58.13 |
| 6/28/2019 |  54.025 | 58.13 |
| 7/1/2019  |  54.225 | 57.65 |
| 7/2/2019  | 54.7758 | 57.65 |
| 7/3/2019  |   55.54 | 57.65 |
| 7/5/2019  |   55.71 | 57.65 |
| 7/8/2019  |   55.96 | 57.65 |
| 7/9/2019  |   56.04 | 57.65 |
| 7/10/2019 |    56.6 | 57.65 |
| 7/11/2019 |   56.92 | 57.65 |
| 7/12/2019 |   57.57 | 57.65 |
| 7/15/2019 |   57.87 | 57.65 |
| 7/16/2019 |   57.46 | 57.65 |
| 7/17/2019 |   57.19 | 57.65 |
| 7/18/2019 |    56.9 | 57.65 |
| 7/19/2019 |   57.32 | 57.65 |
| 7/22/2019 |   57.37 | 57.65 |
| 7/23/2019 |   57.48 | 57.65 |
| 7/24/2019 |   57.11 | 57.65 |
| 7/25/2019 |   56.37 | 57.65 |
| 7/26/2019 |   56.37 | 57.65 |
| 7/29/2019 |   56.54 | 57.65 |
| 7/30/2019 |   56.35 | 57.65 |
| 7/31/2019 |    54.9 | 57.65 |
| 8/1/2019  |   55.16 | 57.87 |
| 8/2/2019  |   52.58 | 57.87 |
| 8/5/2019  |   50.94 | 57.87 |
| 8/6/2019  |    51.6 | 57.87 |
| 8/7/2019  |   51.21 | 57.87 |
| 8/8/2019  |   52.59 | 57.87 |
| 8/9/2019  |   52.04 | 57.87 |
| 8/12/2019 |    51.2 | 57.87 |
| 8/13/2019 |    51.2 | 57.87 |
| 8/14/2019 |   50.13 | 57.87 |
| 8/15/2019 |      46 | 57.87 |
| 8/16/2019 |    46.4 | 57.87 |
| 8/19/2019 |   47.49 | 57.87 |
| 8/20/2019 |   47.92 | 57.87 |
| 8/21/2019 |   48.36 | 57.87 |
| 8/22/2019 |   47.94 | 57.87 |
| 8/23/2019 |   46.43 | 57.87 |
| 8/26/2019 |   46.67 | 57.87 |
| 8/27/2019 |   46.69 | 57.87 |
+-----------+---------+-------+

以下是前 2 个月而不是 1 个月的结果:

任何帮助将不胜感激。

【问题讨论】:

  • 样本数据和预期结果将极大地帮助我们,帮助您。
  • 刚刚添加,谢谢

标签: sql sql-server join sql-update


【解决方案1】:

我相信这应该是您正在寻找的:

DECLARE @monthsBack int = 2

UPDATE t1
    SET myMax = tmp.myMax
FROM PY t1
CROSS APPLY (
    SELECT MAX(myVal) as myMax
    FROM PY t2
    WHERE t2.[date] BETWEEN 
         DATEADD(month, -1 * (@monthsBack+1), dateadd(day, 1, eomonth(t1.[date])))
         AND 
         DATEADD(month, -1, eomonth(t1.[date]))
    ) tmp

我的输出示例:

这一切都在WHERE 子句中,您可以在其中定义您正在查看的范围。上面使用的 WHERE 版本的替代方案是:

WHERE t2.[date] BETWEEN 
  DATEADD(month, -1 * @monthsBack, dateadd(day, 1, dateadd(month, -1, eomonth(t1.[date]))))
  AND 
  DATEADD(month, -1, eomonth(t1.[date]))

如果您希望它工作超过 1 个月,只需将 @monthsback 变量更改为另一个值。

如果您在几年(上一年)内发生变化,如果回溯 1 个月或更长时间会导致这种情况发生,那么您的初始代码将无法工作。

也就是说,因为您没有在以下部分处理这种情况:

DATEPART(yyyy, DATEADD(m, -1, t1.[date])) = t2.[year]

上面截图中我运行生成一些随机样本数据并得到结果的代码是:

create table #py ([date] date, myVal decimal(8, 2))

insert into #py (date, myVal)
values ('5/1/2019',   55.51 ),
('5/2/2019',   54.82 ),
('5/3/2019',   54.18 ),
('5/6/2019',   53.56 ),
('5/7/2019',   52.94 ),
('5/8/2019',   53.13 ),
('5/9/2019',   52.23 ),
('5/10/2019',   51.95 ),
('5/13/2019',   51.06 ),
('5/14/2019',   51.38 ),
('5/15/2019',   57.02 ),
('5/16/2019',   54.12 ),
('5/17/2019',   55.52 ),
('5/20/2019', 55.5513 ),
('5/21/2019',   58.13 ),
('5/22/2019',   55.67 ),
('5/23/2019',   53.94 ),
('5/24/2019',   54.06 ),
('5/28/2019',   53.82 ),
('5/29/2019',  52.855 ),
('5/30/2019',  53.335 ),
('5/31/2019',   52.01 ),
('6/3/2019',  51.485 ),
('6/4/2019',   52.41 ),
('6/5/2019',   53.75 ),
('6/6/2019',   54.21 ),
('6/7/2019',   55.03 ),
('6/10/2019',   55.96 ),
('6/11/2019',   56.73 ),
('6/12/2019',   57.65 ),
('6/13/2019',   55.78 ),
('6/14/2019',   54.66 ),
('6/17/2019',   54.86 ),
('6/18/2019',   55.75 ),
('6/19/2019',   55.77 ),
('6/20/2019',   56.68 ),
('6/21/2019',   56.98 ),
('6/24/2019',   56.69),
('6/25/2019',   56.01 ),
('6/26/2019',   56.36 ),
('6/27/2019',   55.47 ),
('6/28/2019',  54.025 ),
('7/1/2019',  54.225 ),
('7/2/2019', 54.7758 ),
('7/3/2019',   55.54 ),
('7/5/2019',   55.71 ),
('7/8/2019',   55.96 ),
('7/9/2019',   56.04 ),
('7/10/2019',    56.6 ),
('7/11/2019',   56.92 ),
('7/12/2019',   57.57 ),
('7/15/2019',   57.87 ),
('7/16/2019',   57.46 ),
('7/17/2019',   57.19),
('7/18/2019',    56.9),
('7/19/2019',   57.32 ),
('7/22/2019',   57.37 ),
('7/23/2019',   57.48 ),
('7/24/2019',   57.11 ),
('7/25/2019',   56.37 ),
('7/26/2019',   56.37 ),
('7/29/2019',   56.54 ),
('7/30/2019',   56.35 ),
('7/31/2019',    54.9),
('8/1/2019',   55.16 ),
('8/2/2019',   52.58 ),
('8/5/2019',   50.94 ),
('8/6/2019',    51.6 ),
('8/7/2019',   51.21 ),
('8/8/2019',   52.59),
('8/9/2019',   52.04 ),
('8/12/2019',    51.2 ),
('8/13/2019',    51.2 ),
('8/14/2019',   50.13 ),
('8/15/2019',      46 ),
('8/16/2019',    46.4 ),
('8/19/2019',   47.49),
('8/20/2019',   47.92 ),
('8/21/2019',   48.36 ),
('8/22/2019',   47.94 ),
('8/23/2019',   46.43 ),
('8/26/2019',   46.67 ),
('8/27/2019',   46.69);

现在,我们添加数据后,我们可以查询它以获得所需的结果,如上图所示:

declare @monthsback int = 2

select *
FROM #PY t1
CROSS APPLY (
    SELECT MAX(myVal) as myMax
    FROM #PY t2
    WHERE t2.[date] BETWEEN 
         DATEADD(month, -1 * (@monthsBack+1), dateadd(day, 1, eomonth(t1.[date])))
         AND 
         DATEADD(month, -1, eomonth(t1.[date]))
    ) tmp
order by 1 asc

【讨论】:

  • 谢谢拉杜。这非常接近,但结束范围正好达到当前记录。这需要在日历月停止,例如:如果当前记录的日期为 2019 年 4 月 5 日并查找前 2 个月,它应该找到 2019 年 2 月 1 日到 2019 年 3 月 31 日之间的最大值,而不是在 2019 年 2 月 1 日至 2019 年 4 月 5 日之间。
  • @JDG 你的问题并不清楚。它现在应该可以正常工作了,请看一下,如果确实如此,请不要忘记投票/将答案标记为正确。它对我有很大帮助:)
  • 成功了!再次感谢,非常感谢。
猜你喜欢
  • 2011-08-28
  • 1970-01-01
  • 1970-01-01
  • 2017-12-07
  • 1970-01-01
  • 2011-02-05
  • 2022-01-23
  • 2023-04-08
  • 2018-02-03
相关资源
最近更新 更多