尝试使用 MySQL 创建具有同一表中另一列的季节至今平均值的列

Posted

技术标签:

【中文标题】尝试使用 MySQL 创建具有同一表中另一列的季节至今平均值的列【英文标题】:trying to create column with season-to-date averages of values of another column in same table using MySQL 【发布时间】:2016-05-14 06:28:30 【问题描述】:

我正在努力确定 mysql 代码以在我的表“starting_pitcher_stats”中创建一列(平均 park_factor),我想在另一列中包含值的赛季至今季内平均值(park_factor)。我希望按投手和日期对这个赛季平均值进行分组。

理想情况下,表格应如下所示:

    pitcher     park_fac   avg_park_fac       date
    aased001    94         94           1977-07-31
    aased001    100        97           1977-08-06
    aased001    108        100.666      1977-08-11
    aased001    108        102.5        1977-08-16
    aased001    96         101.2        1977-08-21
    aased001    108        102.33       1977-08-26
    aased001    108        103.14       1977-08-31
    aased001    104        103.25       1977-09-05
    aased001    108        103.77       1977-09-10
    aased001    92         102.6        1977-09-16
    aased001    106        102.9        1977-09-22
    aased001    108        103.33       1977-09-27

我使用的代码是:

SELECT Starting_Pitcher, full_park_factor, AVG(full_park_factor), Game_Date
FROM starting_pitcher_stats 
GROUP BY Starting_Pitcher, Game_Date, Game_Number

...结果表的示例如下所示:

pitcher     park_fac   avg_park_fac  date
aased001    94         94.0000      1977-07-31
aased001    100        100.0000     1977-08-06
aased001    108        108.0000     1977-08-11
aased001    108        108.0000     1977-08-16
aased001    96         96.0000      1977-08-21
aased001    108        108.0000     1977-08-26
aased001    108        108.0000     1977-08-31
aased001    104        104.0000     1977-09-05
aased001    108        108.0000     1977-09-10
aased001    92         92.0000      1977-09-16
aased001    106        106.0000     1977-09-22
aased001    108        108.0000     1977-09-27

有人可以帮忙吗?

在此先感谢您的帮助。 李

【问题讨论】:

我不知道您希望我们为您提供什么帮助。考虑提供与所需结果相对应的正确 CREATE 和 INSERT 语句 您好草莓,我只是想创建一个列 avg_Park_factor,它具有对应行值的平均值 + park_factors 列的给定年份内先前日期的行值。跨度> 【参考方案1】:

您需要将同一张桌子上同一投手的所有先前结果加入您的桌子。

我不太确定你如何定义你的季节,但假设它是按日历年,以下查询会产生所需的输出。

SELECT
    a.Starting_Pitcher, a.full_park_factor,
    AVG(b.full_park_factor), a.Game_Date, a.Game_Number
FROM starting_pitcher_stats a
INNER JOIN starting_pitcher_stats b
    ON a.Starting_Pitcher = b.Starting_Pitcher
    AND (b.Game_Date < a.Game_Date OR
         (b.Game_Date = a.Game_Date AND b.Game_Number <= a.Game_Number))
    AND YEAR(b.Game_Date) = YEAR(a.Game_Date)
GROUP BY a.Starting_Pitcher, a.Game_Date, a.Game_Number;

您似乎想用此计算的结果更新表中的列。这可以通过使用触发器进行实时更新来实现,该触发器在您插入或更新现有数据或使用视图时更新列。

CREATE VIEW starting_pitcher_stats_with_average AS
SELECT
    a.Starting_Pitcher, a.full_park_factor,
    AVG(b.full_park_factor), a.Game_Date, a.Game_Number
FROM starting_pitcher_stats a
INNER JOIN starting_pitcher_stats b
    ON a.Starting_Pitcher = b.Starting_Pitcher
    AND (b.Game_Date < a.Game_Date OR
         (b.Game_Date = a.Game_Date AND b.Game_Number <= a.Game_Number))
    AND YEAR(b.Game_Date) = YEAR(a.Game_Date)
GROUP BY a.Starting_Pitcher, a.Game_Date, a.Game_Number;

在您自己的答案中,您创建了一个过程来一次性更新表中所有记录的平均列,因此您可能不希望在插入数据时更新列,而只需添加按需为所有行取平均值。在这种情况下,您可以编写一个UPDATE 语句,其中包含上面的SELECT 查询作为子查询。因为 MySQL 不能为 UPDATE 和子查询使用同一个表,所以您必须将子查询包装在另一个 SELECT 中,以便 MySQL 从您的结果中生成一个临时表。

UPDATE starting_pitcher_stats c
SET c.std_F_parkfactor = (
    SELECT d.std_F_parkfactor FROM (
        SELECT
            a.Starting_Pitcher,
            AVG(b.full_park_factor) std_F_parkfactor,
            a.Game_Date, a.Game_Number
        FROM starting_pitcher_stats a
        INNER JOIN starting_pitcher_stats b
            ON a.Starting_Pitcher = b.Starting_Pitcher
            AND (b.Game_Date < a.Game_Date OR
                 (b.Game_Date = a.Game_Date
                  AND b.Game_Number <= a.Game_Number))
            AND YEAR(b.Game_Date) = YEAR(a.Game_Date)
        GROUP BY a.Starting_Pitcher, a.Game_Date, a.Game_Number
    ) d
    WHERE c.Starting_Pitcher = d.Starting_Pitcher
    AND c.Game_Date = d.Game_Date
    AND c.Game_Number = d.Game_Number
);

【讨论】:

是的,我想就是这样 - 倒数第二行可能需要也可能不需要 马特,谢谢!这很好用。现在尝试使用“ALTER TABLE starting_pitcher_stats ADD COLUMN AVG(b.full_park_factor) 将 AVG(b.full_park_factor) 字段作为列添加到表中,但它不起作用...... Game_Number 列只是指游戏编号如果它发生在给定日期,则为双标题(即,0=第 1 场比赛;1=如果发生,则为第 1 场比赛;2=第 2 场比赛)。但我可以将该列添加到代码中. 谢谢。 MySQL doesn't support the use of expressions in default values。您可以编写一个触发器来在插入时更新表中的列,但它只有在您始终按日期顺序输入统计信息时才有效。当您错过一个并稍后输入时,您必须更新表中的所有以下记录。根据您的要求,您最好考虑创建a view from your SELECT statement。 我已经编辑了答案,以反映同一天可以进行不止一场比赛的事实,Game_Number 引用了这一事实。 谢谢马特。我将研究其他选项,尤其是创建视图。但是后来我想知道以后在 R 之类的统计程序中分析该表中的数据(包括视图中的 avg_Park_factor 列中的数据)的可行性。该列中的数据是否仍然“可用”并且可用于数据操作分析程序即使只存储在一个视图中?我想知道是否可以为 average_park_factor 创建一个可存储的数据列,如果我可以在不使用 AVG 表达式的情况下重新创建表达式的功能,例如 avg_park_factor=@park_factor+park_factor/@row number?【参考方案2】:

更新:这是一种将给定季节的季节至今(季节内)公园因子平均值存储在列中的方法,在这种情况下,它是同一表中另一列值的平均值,使用存储过程。它基本上通过除以 row_number 来计算平均值,row_number 对应于在计算此变量时循环的值的行数。如果您已经收集了想要一次性更新或很少更新的数据,则此方法有效,但正如 Matt Raines 所暗示的,可能必须比他建议的方法更频繁地运行。如果表格会经常更新连续几天比赛结果的数据,至少每天一次,我认为使用他的方法会减少劳动强度。请告诉我可以消除什么:

DROP PROCEDURE IF EXISTS std_park_factor_avg;
DELIMITER $$
CREATE PROCEDURE std_park_factor_avg()
BEGIN
    DECLARE pit_id CHAR(10);
    DECLARE lgID CHAR (2); 
    DECLARE YEARID INT;
    DECLARE gdate DATE;
    DECLARE seq INT;
    DECLARE F_park_factor INT;
    DECLARE RNUMBER INT;
    DECLARE accum_F_parkfactor REAL;
    DECLARE accum_row_number INT;
    DECLARE accum_avg_F_parkfactor REAL;
    DECLARE prev_year YEAR(4);
    DECLARE end_of_cursor BOOLEAN;

    DECLARE no_table CONDITION FOR SQLSTATE '42S02';

    DECLARE c1 CURSOR FOR
      SELECT Starting_Pitcher, lg_ID, YEAR_ID, Game_Date, Game_Number, full_park_factor, ROW_NUMBER 
        FROM starting_pitcher_stats
        GROUP BY Starting_Pitcher, lg_ID, YEAR_ID, Game_Date, Game_Number;

    DECLARE CONTINUE HANDLER FOR NOT FOUND
      SET end_of_cursor := TRUE;

    SET end_of_cursor := FALSE;  -- reset
    SET prev_year := 0;          -- reset control-break

    OPEN c1;

    fetch_loop: LOOP
      FETCH c1 INTO pit_id, lgID, YEARID, gdate,seq, F_park_factor, RNUMBER;
      IF end_of_cursor THEN
        LEAVE fetch_loop;
      END IF;

      -- check control-break conditions
      IF YEAR(gdate) != prev_year THEN
       SET accum_F_parkfactor := 0.0;
       SET RNUMBER:= 1.0;
       SET accum_avg_F_parkfactor := 0.0;
        SET prev_year := YEAR(gdate);
      END IF;

     SET accum_F_parkfactor := accum_F_parkfactor + F_park_factor;
     SET accum_avg_F_parkfactor := accum_F_parkfactor/RNUMBER;

      UPDATE starting_pitcher_stats
        SET std_F_parkfactor =accum_avg_F_parkfactor
        WHERE Starting_Pitcher = pit_id
          AND lg_ID = lgID 
          AND YEAR_ID = YEARID
          AND Game_Date = gdate
          AND Game_Number = seq;

    END LOOP;
    CLOSE c1;
  END
$$

DELIMITER ;

【讨论】:

以上是关于尝试使用 MySQL 创建具有同一表中另一列的季节至今平均值的列的主要内容,如果未能解决你的问题,请参考以下文章

使用同一表中另一列的数据计数更新一列? [关闭]

根据MySQL中另一列分组的另一列的顺序更新列

如何通过 Pyspark 中同一数据框中另一列的正则表达式值过滤数据框中的一列

使用同一 Dataframe 中另一列的 int 作为索引获取列中的列表值

基于sql中另一列的一列中的最大数据

验证一列大于yii中另一列的日期