2017-05-31 55 views
2

我正在嘗試計算一些關於使用MySQL的體育玩家的統計數據。該數據庫有3個表格。使用MySQL爲每個返回的行執行相關子查詢

的相關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

我想到的是用下面的列結果:

​​
+0

請參閱:[爲什麼我應該爲我認爲是非常簡單的SQL查詢提供一個MCVE?](https://meta.stackoverflow.com/questions/333952/why-should-i-provide-an -mcve-for-what-looks-to-the-very-simple-sql-query) – Strawberry

+0

@Strawberry MVCE添加。 –

+0

感謝您的進度報告 – Strawberry

回答

0

我仍然沒能得到查詢返回預期的結果,但我已經切換到另一個和明顯的方法工作。

我在播放器表中添加了兩個計算列:last_five_matches_avg_ratinglast_five_matches_ratings

每次更新數據庫後,都會執行一個腳本:它遍歷所有玩家,執行第二個查詢以檢索統計數據並將計算出的統計數據存儲在相應的列中。

下面是這個PHP腳本(它使用學說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 
; 

這不正是我想要的開始,但它確實訣竅(這個數據庫的更新數量很少),而且速度很快。

我希望它可以幫助別人。