如何在MySQL子查询中使用GROUP BY

时间:2014-07-09 11:44:19

标签: mysql sql group-by subquery

我使用phpMyAdmin提交查询。在子查询中使用GROUP BY时,整个应用程序只会挂起而没有错误,直到我重新启动浏览器。

我有三个表:files存储有关上传文件的信息,file_category定义文件的可用类别,file_category_r存储文件和类别之间的关系。

我想计算每个类别有多少个文件,但有些文件可以在files表中有多个条目,所以我需要按files.filename对它们进行分组。

我尝试了两种不同的方法,都导致了一个问题:

SELECT 
    fc.*, 
    (SELECT COUNT(*) FROM file_category_r
        WHERE file_category_r.category_id = fc.id 
        AND file_category_r.file_id IN 
            (SELECT f2.id FROM 
                (SELECT * FROM files f3 GROUP BY f3.filename) f2 
                    WHERE f2.mandant_id = 1) 
    ) as file_count 
FROM file_category fc ORDER BY name ASC

SELECT 
    fc.*, 
    (SELECT COUNT(*) FROM file_category_r
        WHERE file_category_r.category_id = fc.id 
        AND file_category_r.file_id IN 
            (SELECT id FROM files WHERE mandant_id = 1 GROUP BY filename) 
    ) as file_count 
FROM file_category fc ORDER BY name ASC

我没有看到我的查询有问题,单独运行子查询就可以了。即使删除GROUP BY也会返回结果,但结果是错误的,因为它计算重复值。

以下是表架构:

CREATE TABLE IF NOT EXISTS `files` (
  `id` bigint(20) unsigned NOT NULL,
  `project_id` bigint(20) unsigned DEFAULT NULL,
  `customer_id` bigint(20) unsigned DEFAULT NULL,
  `opportunity_id` int(11) DEFAULT NULL,
  `task_id` bigint(20) unsigned DEFAULT NULL,
  `calendar_event_id` bigint(20) unsigned DEFAULT NULL,
  `mandant_id` tinyint(4) DEFAULT NULL,
  `time` timestamp NULL DEFAULT CURRENT_TIMESTAMP,
  `size` float NOT NULL,
  `mime_type` varchar(100) NOT NULL,
  `filename` text NOT NULL,
  `file` longblob NOT NULL,
  `folder_id` int(11) DEFAULT NULL,
  `user_id` int(11) DEFAULT NULL,
  `is_public` tinyint(1) unsigned NOT NULL DEFAULT '0',
  `description` text,
  `file_link` varchar(500) DEFAULT NULL
) ENGINE=InnoDB  DEFAULT CHARSET=utf8 AUTO_INCREMENT=104832 ;

CREATE TABLE IF NOT EXISTS `file_category` (
  `id` int(11) NOT NULL,
  `name` varchar(200) NOT NULL,
  `parent` int(11) DEFAULT NULL
) ENGINE=InnoDB  DEFAULT CHARSET=utf8 AUTO_INCREMENT=445 ;

CREATE TABLE IF NOT EXISTS `file_category_r` (
  `id` bigint(20) unsigned NOT NULL,
  `file_id` bigint(20) unsigned NOT NULL,
  `category_id` int(11) NOT NULL
) ENGINE=InnoDB  DEFAULT CHARSET=utf8 AUTO_INCREMENT=300346 ;

我做错了什么?表非常大,请求是否可能太重?我没有想法,请帮忙!谢谢!

3 个答案:

答案 0 :(得分:1)

select fc.name, count(*)
from file_category fc
inner join file_category_r fcr on fc.id = fcr.category_id
group by fc.name

不太确定"有些文件可以在files表中有多个条目,所以我需要按files.filename"对它们进行分组。 也许你需要像

这样的东西
select fc.name, count(distinct f.filename)
from file_category fc
inner join file_category_r fcr on fc.id = fcr.category_id
inner join files f on fcr.file_id = f.id
group by fc.name

答案 1 :(得分:0)

通常,使用in会导致查询计划效率低下。您可以尝试使用exists

SELECT fc.*, 
        (SELECT COUNT(*)
         FROM file_category_r fcr
         WHERE fcr.category_id = fc.id AND
               exists (select 1 from files f where f.mandant_id = 1 and fcr.file_id = f.id)
        ) as file_count 
FROM file_category fc
ORDER BY name ASC;

现在,您应该添加索引。从file_category_r(category_id, file_id)files(id, mandant_id)开始。

答案 2 :(得分:0)

我使用的是heidisql,而不是phpmyadmin,你的查询在这里运行正常。也许phpmyadmin在解析你的查询时遇到了问题。

编辑:此外,查询长度有限制。如果您的" in" -statement为long,则mysql将返回phpmyadmin应返回的错误。

但是如果phpmyadmin挂起,我会尝试执行你的查询我的mysqlc或另一个像heidisql这样的mysql客户端。