时间戳转换器

使用 MySQL 为每个返回的行执行相关子查询

日期:2023-05-09     浏览:54    
【中文标题】使用 MySQL 为每个返回的行执行相关子查询【英文标题】:Execute a correlated subquery for each returned row with MySQL 【发布时间】:2017-05-31 08:43:42 【问题描述】:

我正在尝试使用 MySQL 计算一些体育运动员的统计数据。该数据库有 3 个表。

相关Rextester:http://rextester.com/SNAL27886

玩家

球员名单。

+----+---------+-----------+
| id | team_id | lastname  |
+----+---------+-----------+
|  1 |       1 | Moubandje |
|  2 |       2 | Rüfli     |
|  3 |       3 | Selnaes   |
|  4 |       1 | Somália   |
|  5 |       4 | Kerbrat   |
+----+---------+-----------+

匹配

团队列表。

+----+--------------+--------------+-----+
| id | home_team_id | away_team_id | day |
+----+--------------+--------------+-----+
|  1 |            1 |            2 |   1 |
|  2 |            2 |            1 |   2 |
|  3 |            2 |            3 |   3 |
|  4 |            3 |            4 |   4 |
|  5 |            3 |            5 |   5 |
+----+--------------+--------------+-----+

player_match

每场比赛球员的统计数据。

+-----------+----------+-----------+------------+-------+
| player_id | match_id | rating    | substitute | goals |
+-----------+----------+-----------+------------+-------+
|         1 |        1 |         6 |          0 |     2 |
|         2 |        2 |         5 |          1 |     0 |
|         1 |       10 |         3 |          0 |     0 |
+-----------+----------+---------+-----------+----------+

这是我的查询,用于计算有关球员的各种统计数据(例如他的进球数或他的全球平均评分):

SELECT
  p.id AS p_id,
  p.lastname AS lastname,
  p.team_id as team_id,
  AVG(pm.rating) AS avg_rating,
  COUNT(pm.player_id) AS nb_matches,
  SUM(pm.substitute) AS nb_matches_substitute,
  SUM(pm.goals) AS goals,
  (SUM(pm.goals) / COUNT(pm.player_id)) AS goals_per_matches
FROM
  player p
  INNER JOIN player_match pm ON pm.player_id = p.id
  INNER JOIN `match` m ON pm.match_id = m.id AND (m.home_team_id = p.team_id OR m.away_team_id = p.team_id)
GROUP BY
  p.id,
  p.lastname,
  p.team_id
ORDER BY
  avg_rating DESC, lastname ASC
;

我还想计算该球员在他的球队最近 5 场比赛中的平均评分(如果该球员没有参加过比赛,他的评分必须为 0)。然后,我想按这个特定的平均评分对列表的结果进行排序。

这是我的查询,用于检索给定球员在他的球队最近 5 场比赛中的平均评分以及每场比赛的评分作为字符串:

SELECT
  SUM(pm1.rating) / COUNT(m1.id) last_5_matches_rating,
  GROUP_CONCAT(CONCAT(m1.day, '=', COALESCE(pm1.rating, '~')) ORDER BY m1.day)
FROM
  `match` m1
  INNER JOIN (
    SELECT m2.id, m2.home_team_id, m2.away_team_id
    FROM `match` m2
    AND (m2.home_team_id=1 OR m2.away_team_id=1)
    ORDER BY m2.day DESC
    LIMIT 5
  ) last_5_games ON m1.id = last_5_games.id
  LEFT JOIN player_match pm1 ON m1.id = pm1.match_id AND pm1.player_id=4

这是第 1 队的第 4 名球员的结果。

有没有办法将最后一个查询作为前一个查询的子查询执行,并按last_5_matches_rating 排序结果?

我期望的是以下列的结果:

| id | lastname | team_id | avg_rating | last_5_matches_rating | nb_matches | ...

【问题讨论】:

见:Why should I provide an MCVE for what seems to me to be a very simple SQL query? @Strawberry MVCE 添加。 感谢进度报告 【参考方案1】:

我仍然无法获得返回预期结果的查询,但我已改用另一种明显的方式来完成这项工作。

我在播放器表中添加了两个计算列:last_five_matches_avg_rating 和 last_five_matches_ratings。

每次数据库更新后,都会执行一个脚本:它遍历所有玩家,执行第二个查询以检索统计数据并将这些计算的统计数据存储在相应的列中。

这是这个 PHP 脚本(它使用 Doctrine ORM):

<?php

namespace App;

use App\Entity\Player;
use Doctrine\Common\Persistence\ManagerRegistry;

class StatsComputer

    private $doctrine;

    public function __construct(ManagerRegistry $doctrine)
    
        $this->doctrine = $doctrine;
    

    public function update()
    
        $manager = $this->doctrine->getManager();
        $stmt = $manager->getConnection()->prepare(<<<SQL
SELECT
  SUM(pm1.rating) / COUNT(m1.id) last_5_matches_avg_rating,
  GROUP_CONCAT(COALESCE(pm1.rating, '0')) ORDER BY m1.day) last_5_matches_ratings
FROM
  `match` m1
  INNER JOIN (
    SELECT m2.id, m2.home_team_id, m2.away_team_id
    FROM `match` m2
    AND (m2.home_team_id=:team_id OR m2.away_team_id=:team_id)
    ORDER BY m2.day DESC
    LIMIT 5
  ) last_5_games ON m1.id = last_5_games.id
  LEFT JOIN player_match pm1 ON m1.id = pm1.match_id AND pm1.player_id=:player_id
SQL
);

        foreach ($this->doctrine->getRepository(Player::class)->findAll() as $player) 
            /**
             * @var $player Player
             */
            $stmt->execute(['team_id' => $player->team->id, 'player_id' => $player->id]);
            $results = $stmt->fetch();

            $player->last5MatchesAvgRating = $results['last_5_matches_avg_rating'];
            $player->last5MatchesRatings = array_map('intval', explode(',', $results['last_5_matches_ratings']));
        

        $manager->flush();
    

以及第一个查询的更新版本:

SELECT
  p.id AS p_id,
  p.lastname AS lastname,
  p.team_id as team_id,
  p.last_5_matches_avg_rating as last_5_matches_avg_rating,
  p.last_5_matches_ratings as last_5_matches_ratings,
  AVG(pm.rating) AS avg_rating,
  COUNT(pm.player_id) AS nb_matches,
  SUM(pm.substitute) AS nb_matches_substitute,
  SUM(pm.goals) AS goals,
  (SUM(pm.goals) / COUNT(pm.player_id)) AS goals_per_matches
FROM
  player p
  INNER JOIN player_match pm ON pm.player_id = p.id
  INNER JOIN `match` m ON pm.match_id = m.id AND (m.home_team_id = p.team_id OR m.away_team_id = p.team_id)
GROUP BY
  p.id,
  p.lastname,
  p.team_id,
  p.last_5_matches_avg_rating,
  p.last_5_matches_ratings
ORDER BY
  last_5_matches_avg_rating DESC, avg_rating DESC, lastname ASC
;

这并不是我最初想要的,但它确实有效(这个数据库的更新次数很少)而且速度很快。

我希望它可以帮助某人。

【讨论】:

相关文章

mysql的子查询相关知识,少但是精(代码片段)

{...1)不相关子查询:一条Sql语句中含有多条SELECT语句,先执行子查询,再执行外查询,子查询可对立运行          关键字:(1)先子查询,再外查询              (2)可以对立运行,即可以单独运...}

oracle-子查询top-n(代码片段)

{...,外层的语句可以把内嵌的子查询返回的结果当成一张表使用,子查询结果可以作为一个虚表被使用。注意,子查询要用括号括起来。子查}

mysql:使用like返回重复的行数

{】mysql:使用like返回重复的行数【英文标题】:mysql:usinglikereturnduplicaterowcount【发布时间】:2013-03-2618:19:47【问题描述】:下面有问题表1第一种情况:postcodeLS11LS第二种情况:postcodeLS11LS表2postcode|regionLS1|LeedsLS11|Leeds我正在使用以...}

如何根据连接查询中的一列返回最大行? [复制]

{】如何根据连接查询中的一列返回最大行?[复制]【英文标题】:Howtoreturnthemaxrowbasedononecolumninjoinquery?[duplicate]【发布时间】:2019-06-1507:49:43【问题描述】:我有一个查询,它从几个表中返回一个带有一些ID的结果集。如果得到两...}

mysql子查询使用方式(代码片段)

{阅读目录阐述子查询分类按照返回结果的行列数分类按子查询出现在主查询的位置分类预备数据部门表departments员工表employees职位信息表jobs位置表locations薪资等级表job_grades查询数据示例select后面的子查询示例1查询每个部门员工...}

mysql子查询使用方式(代码片段)

{阅读目录阐述子查询分类按照返回结果的行列数分类按子查询出现在主查询的位置分类预备数据部门表departments员工表employees职位信息表jobs位置表locations薪资等级表job_grades查询数据示例select后面的子查询示例1查询每个部门员工...}

JOIN 语法中的 MySQL 相关子查询

{...'中的未知列\'outertable.id\'”。这种查询可以吗?内部查询使用GROUPBY将行转为}

MySQL 索引优化与子查询与左连接

{...2012-11-2607:04:46【问题描述】:我创建了2个查询,我可以使用它们来执行相同的功能。它们都包含我想合并到一个查询中但我无法合并的属性。查询1-给了我想要的结果。慢(~0.700秒)问题2-给了我很多我忽略和跳过的行。快速(~...}

PHP MySQL 相同的查询返回不同的行数

{...ofrows【发布时间】:2021-08-1707:37:54【问题描述】:我正在使用php和mysql从数据库中插入和选择数据。昨天我发现了一个新的“错误”,即:我在网站上使用了两次相同的查询——相同的查询——但结果不同当然我不明白为什么结...}

MySQL 无法在 from 子句中为子查询创建视图

{...。我做了联合查询。我发现我构建的查询为不在Top10中的每个系统名称返回了“其他”记录,因此我在select中选择了所有“其他”的总和。这导致我出现错误代码1349。有}

Copyright ©2021 时间戳转换器 小常识 114pp | 陕ICP备18005036号