尝试使用 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 yourSELECT
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 创建具有同一表中另一列的季节至今平均值的列的主要内容,如果未能解决你的问题,请参考以下文章
如何通过 Pyspark 中同一数据框中另一列的正则表达式值过滤数据框中的一列