【问题标题】:SQL Average based on multiple conditions基于多个条件的 SQL 平均值
【发布时间】:2020-12-02 07:56:08
【问题描述】:

我有下表:

+-----------+----------+-------------+----------------+---------------+
| FirstName | LastName | SessionDate |  SessionTitle  | TotalDistance |
+-----------+----------+-------------+----------------+---------------+
| Player    | Striker  |  05.08.2020 | Entire Session |          10.0 |
| Player    | Striker  |  05.08.2020 | 1v1            |           5.0 |
| Player    | Striker  |  06.08.2020 | Entire Session |          12.0 |
| Coach     | Defender |  06.08.2020 | Entire Session |           7.0 |
+-----------+----------+-------------+----------------+---------------+

我需要做的是为每个玩家单独计算 totalDistance 的平均值。平均值应仅使用值计算,其中 SessionTitle 为“EntireSession”,并且仅适用于每行的最后 50 天。所以预期的结果应该是这样的:

+-----------+----------+-------------+----------------+---------------+---------+
| FirstName | LastName | SessionDate |  SessionTitle  | TotalDistance | average |
+-----------+----------+-------------+----------------+---------------+---------+
| Player    | Striker  |  05.08.2020 | Entire Session |          10.0 |    10.0 |
| Player    | Striker  |  05.08.2020 | 1v1            |           5.0 |    10.0 |
| Player    | Striker  |  06.08.2020 | Entire Session |          12.0 |    11.0 |
| Coach     | Defender |  06.08.2020 | Entire Session |           7.0 |     7.0 |
+-----------+----------+-------------+----------------+---------------+---------+

我尝试过这样的事情,但是当添加更多行时它非常慢:

SELECT t1.FirstName, 
t1.LastName, 
t1.SessionDate, 
t1.SessionTitle, 
t1.TotalDistance, 
(SELECT (AVG(t2.TotalDistance) FROM myTable t2 WHERE t1.FirstName = t2.FirstName AND t1.LastName = t2.LastName AND t2.SessionTitle = 'EntireSession' AND t2.SessionDate <= DATEADD(DAY,50,t1.SessionDate)) as average
FROM myTable t1

它在 Azure SQL-Server 上运行 在 select 语句中如何以最快的方式完成这项工作?

提前致谢!

【问题讨论】:

  • 请展示你的尝试

标签: sql sql-server average


【解决方案1】:

我们可以在这里使用AVG作为解析函数:

SELECT *, AVG(CASE WHEN SessionTitle = 'Entire Session' THEN TotalDistance END)
              OVER (PARTITION BY LastName, FirstName) AS average
FROM yourTable;

这里的策略是计算属于每个人的每组记录的平均总距离。我们使用CASE 表达式,当会话标题恰好是Entire Session 时,它将返回TotalDistance。否则,它会返回NULL,默认情况下会被AVG 函数忽略。

【讨论】:

  • 非常感谢您为我指明了正确的方向!还有一个问题:我如何在这个查询中使用 SessionDate。我只想计算每行最后 50 天的平均值。这种方法还有可能吗
  • 是的,还可以通过包含WHERE 子句来按日期过滤。但是,确切的语法是高度特定于数据库供应商的。因此,您应该编辑您的问题并告诉我们您的确切数据库(例如 MySQL、SQL Server、Oracle、Postgres 等)。
  • 我更改了需求和预期的输出表,还添加了数据库类型
【解决方案2】:

不幸的是,“过去 50 天”部分在 SQL Server 中存在问题,因为它不支持具有日期/时间间隔的 range 窗口框架。这排除了简单的使用。一个窗口函数(除非你每天都有数据)。

但是,您可以使用 apply 轻松解决此问题:

select t1.*, t2.average
from mytable t1 outer apply
     (select avg(t2.total_distance) as average
      from mytable t2
      where t2.FirstName = t1.FirstName and
            t2.LastName = t1.LastName and
            t2.SessionTitle = 'EntireSession' and
            t2.SessionDate >= DATEADD(DAY, -50, t1.SessionDate) and
            t2.SessionDate <= t1.SessionDate
     ) t2;

这对你想要做的事情来说是正确的。否则,它类似于相关子查询。

接下来,您需要一个索引来促进此计算。我建议在mytable(lastname, firstname, sessiontitle, sessiondate, total_distance) 上建立一个索引。

【讨论】:

    猜你喜欢
    • 2015-04-11
    • 2023-03-18
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多