2012-01-04 28 views
2

我有以下MySQL查询:我该如何重构这个MySQL查询?

(SELECT c.Channel as name, count(*) as total_episode 
FROM (
    SELECT a.aid, a.vid 
    FROM videoItem v INNER JOIN aid2vid a USING(vid) 
    GROUP BY a.aid 
) a1 INNER JOIN channelListingItem c USING(aid) 
GROUP BY c.Channel 
) 
UNION 
(SELECT c1.Channel as name, 0 as total_episode 
FROM channelListingItem c1 LEFT JOIN (
    SELECT c.Channel FROM (
     SELECT a.aid, a.vid 
     FROM videoItem v INNER JOIN aid2vid a USING(vid) 
     GROUP BY a.aid 
    ) a1 INNER JOIN channelListingItem c USING(aid) 
    GROUP BY c.Channel 
) c2 USING(Channel) 
WHERE c2.Channel is null 
GROUP BY name 
); 

基本上,这种说法确实是让每个通道正确的计数插曲&为渠道W/O VID在随后的表(videoItem)分配为零。

注意

SELECT a.aid, a.vid 
FROM videoItem v 
INNER JOIN aid2vid a USING(vid) 
GROUP BY a.aid 

被复制了两次,这说明MySQL的发言中,我没有看到MySQL的重复使用查询结果。

+----+--------------+------------+------+----------+---------+---------+----------+------+---------------------------------+ 
| id | select_type | table  | type | pos_keys | key  | key_len | ref  | rows | Extra       | 
+----+--------------+------------+------+----------+---------+---------+----------+------+---------------------------------+ 
| 1 | PRIMARY  | <derived2> | ALL | NULL  | NULL | NULL | NULL  | 313 | Using temporary; Using filesort | 
| 1 | PRIMARY  | c   | ALL | idx_vid | NULL | NULL | NULL  | 616 | Using where; Using join buffer | 
| 2 | DERIVED  | a   | ALL | vid  | NULL | NULL | NULL  | 1015 | Using temporary; Using filesort | 
| 2 | DERIVED  | v   | ref | idx_vid | idx_vid | 32  | db.a.vid | 10 | Using index      | 
| 3 | UNION  | c1   | ALL | NULL  | NULL | NULL | NULL  | 616 | Using temporary; Using filesort | 
| 3 | UNION  | <derived4> | ALL | NULL  | NULL | NULL | NULL  | 28 | Using where; Not exists   | 
| 4 | DERIVED  | <derived5> | ALL | NULL  | NULL | NULL | NULL  | 313 | Using temporary; Using filesort | 
| 4 | DERIVED  | c   | ALL | idx_vid | NULL | NULL | NULL  | 616 | Using where; Using join buffer | 
| 5 | DERIVED  | a   | ALL | vid  | NULL | NULL | NULL  | 1015 | Using temporary; Using filesort | 
| 5 | DERIVED  | v   | ref | idx_vid | idx_vid | 32  | db.a.vid | 10 | Using index      | 
|NULL| UNION RESULT | <union1,3> | ALL | NULL  | NULL | NULL | NULL  | NULL |         | 
+----+--------------+------------+------+----------+---------+---------+----------+------+---------------------------------+ 
11 rows in set (0.02 sec) 

我该如何重构这个MySQL语句? MySQL语句中还有不错的重构工具吗?

谢谢。

+0

它有什么问题?你为什么要重构? – 2012-01-04 07:18:18

+0

你可以尝试Toad for Mysql工具,它是免费的。 – rkosegi 2012-01-04 07:18:26

+0

@SergioTulentsev:解释附加的结果。 – user1045217 2012-01-04 08:09:24

回答

1

这一个似乎为我工作:

select Channel as name,count(distinct a1.aid) as total_episode 
from channelListingItem c 
left join 
(
select a.aid, a.vid 
from videoItem v INNER JOIN aid2vid a USING(vid) 
) a1 on a1.aid = c.aid 
group by Channel; 

从我可以看到你在内嵌视图使用两倍以下查询:

SELECT a.aid, a.vid 
FROM videoItem v INNER JOIN aid2vid a USING(vid) 
GROUP BY a.aid 

是用于获取存在于videoItemaid2vid中的aidvid值的明确列表。我将内联视图中的GROUP BY替换为COUNT(DISTINCT)以实现同样的效果,因为您没有在查询的内联视图部分使用任何聚合函数。

我认为你不需要将查询拆分成由一个联合连接起来的两部分,即第1部分使情节数> 0,第2部分使情节数= 0。这可以在一个GROUP BY中实现。

希望这会有所帮助!

+1

这对我也适用。虽然下面使用COALESCE的结果会产生相同的结果,但MySQL解释似乎对此答案有利。所以我选择了这一个。 – user1045217 2012-01-04 09:14:06

1

我可以这样做,但我相信遵循以提供与原始查询相同的结果。

它的要点是

  • total_episode字段添加到您的LEFT JOIN
  • 使用COALESCE返回total_episode值或0

SQL语句

SELECT c1.Channel as name 
     , COALESCE(total_episode, 0) 
FROM channelListingItem c1 
     LEFT JOIN ( 
      SELECT c.Channel 
        , count(*) as total_episode 
      FROM (
        SELECT a.aid 
          , a.vid 
        FROM videoItem v 
          INNER JOIN aid2vid a ON a.vid = v.vid 
        GROUP BY 
          a.aid 
        ) a1 
        INNER JOIN channelListingItem c ON c.aid = a1.aid 
      GROUP BY 
        c.Channel 
     ) c2 ON c2.Channel = c1.Channel 
    GROUP BY 
     name