【问题标题】:Combine points from separate tables in a loop在循环中组合来自不同表格的点
【发布时间】:2014-01-02 05:23:56
【问题描述】:

所以我加入了一个奇幻电影联盟(比如足球,但不是球员,而是你起草电影),我为它运营网站。我基本上想用 MySQL 和 PHP 做的是:在主页上列出当前年份 (1) 的每部电影,并让它显示每部电影的总分。每部电影的总分均基于以下公式:

metacritic + (imdb*10) + top_bottom + power(receipts,(2/9)) + ALL OTHER AWARDS POINTS

我的问题是所有的奖励积分都放在第二张桌子上,真的是两张。一个表称为“awards”,其中包含所有奖项名称和积分值,第二个表“awards_won”记录每部电影获得或提名的所有各种奖项。

我相信我想要做的是使用基于“awards_won.film_nposed”和/或“awards_won.film_won”是否 = 1 的子查询来计算每部电影的奖励积分。

这段代码几乎可以满足我的要求:

SELECT title,
       (  select sum(awards.nom_points)
          from awards_won
          left join awards on awards.id = awards_won.award_id
          where movie_id = 25 and awards_won.film_nominated = 1
           ) as total_nom_points,
       (  select sum(awards.win_points)
          from awards_won
          left join awards on awards.id = awards_won.award_id
          where movie_id = 25 and awards_won.film_won = 1
           ) as total_win_points,
       ( select total_win_points + total_nom_points) as total_award_points
FROM movies
LEFT JOIN awards_won on awards_won.movie_id = movies.id
WHERE movie_id = 25 and movies.year_id = 1;

除了我不能在循环中使用“where movie_id = 25”,如果我想为每部电影都这样做......所以这就是我卡住的地方。希望这是有道理的。

以下是表格说明:

CREATE TABLE `movies` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`year_id` int(2) NOT NULL,
`title` varchar(100) NOT NULL,
`release_date` date DEFAULT NULL,
`metacritic` int(3) NOT NULL,
`imdb` decimal(2,1) NOT NULL,
`top_bottom` int(3) NOT NULL,
`receipts` int(10) NOT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

CREATE TABLE `awards` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`festival_id` int(2) NOT NULL,
`award_title` varchar(100) NOT NULL,
`nom_points` int(2) NOT NULL,
`win_points` int(2) NOT NULL,
PRIMARY KEY (`id`),
UNIQUE KEY `award_title_and_festival` (`award_title`,`festival_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

CREATE TABLE `awards_won` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`award_id` int(2) NOT NULL,
`movie_id` int(2) NOT NULL,
`nominee_name` varchar(100) NOT NULL,
`film_nominated` tinyint(1) NOT NULL,
`film_won` tinyint(1) NOT NULL,
PRIMARY KEY (`id`),
UNIQUE KEY `year_award_title_id` (`award_id`,`movie_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

PS:我了解如何在 PHP 中使用 foreach 循环显示数组变量,因此 SQL 语句是我的主要问题。提前致谢!


样本数据:

 INSERT INTO `movies` (id, year_id, title, release_date, metacritic, imdb, top_bottom, receipts) 
 VALUES (1,1,'All Is Lost','2013-10-18',87,7.4,7,5947690); 
 INSERT INTO awards (id, festival_id, award_title, nom_points, win_points) 
 VALUES (1,3,'Best Picture',4,16), (2,3,'Best Lead Actor',4,16), (3,3,'Best Score',2,8); 
 INSERT INTO awards_won (id, award_id, movie_id, nominee_name, film_nominated, film_won) 
 VALUES (1,1,1,'All Is Lost',1,0), (2,2,1,'Robert Redford',1,1), (3,3,2,'Hans Zimmer',1,0);

这适用于一部电影,我只需要一个循环

SELECT title, 
      ( select sum(awards.nom_points) 
        from awards_won 
        left join awards on awards.id = awards_won.award_id 
        where movie_id = 1 
          and awards_won.film_nominated = 1
      ) as total_nom_points, 
      ( select sum(awards.win_points) 
        from awards_won 
        left join awards on awards.id = awards_won.award_id 
        where movie_id = 1 
          and awards_won.film_won = 1
      ) as total_win_points, 
      ( select IFNULL(total_win_points,0) + IFNULL(total_nom_points,0)
      ) as total_award_points 
FROM movies 
LEFT JOIN awards_won on awards_won.movie_id = movies.id 
WHERE movie_id = 1 
  and movies.year_id = 1;

这将为电影 1 产生 8 个 total_nom_points、16 个 total_win_points 和 24 个 total_award_points

【问题讨论】:

  • 你能提供样本记录和你想要的结果吗?
  • @Walter 给你:INSERT INTO movies` (id, year_id, title, release_date, metacritic, imdb, top_bottom, @987 @) VALUES (1,1,'All Is Lost','2013-10-18',87,7.4,7,5947690);插入awards (id, festival_id, award_title, nom_points, win_points) 值 (1,3,'最佳图片',4,16), (2,3,'Best Lead演员',4,16); (3,3,'最佳成绩',2,8);插入awards_won (id, award_id, movie_id, nominee_name, film_nominated, film_won) 值 (1,1,1,'All Is Lost',1,0), ( 2,2,1,'罗伯特·雷德福',1,1); (3,3,2,'Hans Zimmer',1,0);`
  • 这适用于一部电影,我只需要一个循环SELECT title, (select sum(awards.nom_points) from awards_won left join awards on awards.id = awards_won.award_id where movie_id = 1 and awards_won.film_nominated = 1) as total_nom_points, (select sum(awards.win_points) from awards_won left join awards on awards.id = awards_won.award_id where movie_id = 1 and awards_won.film_won = 1) as total_win_points, (select IFNULL(total_win_points,0) + IFNULL(total_nom_points,0)) as total_award_points FROM movies LEFT JOIN awards_won on awards_won.movie_id = movies.id WHERE movie_id = 1 and movies.year_id = 1;
  • 这将为电影 1 产生 8 个 total_nom_points、16 个 total_win_points 和 24 个 total_award_points

标签: php mysql


【解决方案1】:

试试这个查询:

  SELECT m.id,
         m.title,
         sum(if(aw.film_nominated = 1,a.nom_points,0)) AS total_nom_points,
         sum(if(aw.film_won = 1,a.win_points,0)) AS total_win_points,
         sum(if(aw.film_nominated = 1,a.nom_points,0)) 
         +
         sum(if(aw.film_won = 1,a.win_points,0))  AS TOTAL_AWARD_POINTS
  FROM awards_won aw
  JOIN movies m ON m.id = aw.movie_id
  LEFT JOIN awards a ON a.id = aw.award_id 
  WHERE 1 IN (aw.film_nominated,aw.film_won)
    AND m.year_id = 1
  GROUP BY m.id
;

演示:http://www.sqlfiddle.com/#!2/d804d9/7


使用外连接显示所有电影,即使它们在 awards 表中没有任何记录。
这是一个使用RIGHT JOIN的例子:

  SELECT m.id,
         m.title,
         sum(if(aw.film_nominated = 1,a.nom_points,0)) AS total_nom_points,
         sum(if(aw.film_won = 1,a.win_points,0)) AS total_win_points,
         sum(if(aw.film_nominated = 1,a.nom_points,0)) 
         +
         sum(if(aw.film_won = 1,a.win_points,0)) 
           AS TOTAL_AWARD_POINTS
  FROM awards_won aw
  RIGHT JOIN movies m ON m.id = aw.movie_id
  LEFT JOIN awards a ON a.id = aw.award_id 
  WHERE ( 1 IN (aw.film_nominated,aw.film_won)
          OR aw.id IS NULL
         )
    AND m.year_id = 1
  GROUP BY m.id
;

并使用LEFT JOIN(这里的表格顺序不同):

  SELECT m.id,
         m.title,
         sum(if(aw.film_nominated = 1,a.nom_points,0)) AS total_nom_points,
         sum(if(aw.film_won = 1,a.win_points,0)) AS total_win_points,
         sum(if(aw.film_nominated = 1,a.nom_points,0)) 
         +
         sum(if(aw.film_won = 1,a.win_points,0)) 
           AS TOTAL_AWARD_POINTS
  FROM movies m
  LEFT JOIN awards_won aw ON m.id = aw.movie_id
  LEFT JOIN awards a ON a.id = aw.award_id 
  WHERE ( 1 IN (aw.film_nominated,aw.film_won)
          OR aw.id IS NULL
         )
    AND m.year_id = 1
  GROUP BY m.id
;

演示:http://www.sqlfiddle.com/#!2/4d108/6

请注意这两个查询中的附加条件,否则它们将无法按预期工作:

  WHERE ( 1 IN (aw.film_nominated,aw.film_won)
          OR aw.id IS NULL
         )

【讨论】:

  • 这很好用,谢谢!一个问题,有没有一种方法可以编辑它以显示所有电影,即使它们没有任何奖励积分?
  • 我在答案中附加了两个示例。
  • 壮观,非常感谢!从您的帮助中学到了很多东西。
【解决方案2】:

试试这个:

SELECT title, IFNULL(nom_points.`value`,0) as total_nom_points, 
    IFNULL(win_points.`value`,0) as total_win_points, 
    (IFNULL(nom_points.`value`,0) + IFNULL(win_points.`value`,0)) as total_award_points
FROM movies
LEFT JOIN (  SELECT movie_id, sum(awards.nom_points) as `value`
    FROM awards_won
    LEFT JOIN awards on awards.id = awards_won.award_id
    WHERE awards_won.film_nominated = 1
    GROUP BY movie_id
   ) as nom_points on nom_points.movie_id = movies.id
LEFT JOIN (  select movie_id, sum(awards.win_points) AS `value`
  FROM awards_won
  LEFT JOIN awards on awards.id = awards_won.award_id
  WHERE awards_won.film_won = 1
  GROUP BY movie_id
   ) as win_points on win_points.movie_id = movies.id
WHERE movies.year_id = 1;

检查这个fiddle

【讨论】:

  • 谢谢,太好了!有什么方法可以将“total_award_points”添加到 select 语句中的其他字段?像这样:metacritic + (imdb*10) + top_bottom + power(receipts,(2/9)) + total_award_points as single_movie_total?
  • 不,但你可以这样做(metacritic + (imdb*10) + top_bottom + power(receipts,(2/9)) + (nom_points.value` + win_points.value)) as single_movie_total`
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-01-07
  • 1970-01-01
  • 1970-01-01
  • 2021-05-19
  • 1970-01-01
相关资源
最近更新 更多