如何指定哪些行应该被 GROUP BY 保留,哪些应该被折叠

How to specify which rows should be kept by GROUP BY and which should be collapsed

我正在开发的应用程序包含用户可以创建相册并将图像上传到其中的部分。该应用程序会创建多个调整大小的图像,以便不会向用户提供大版本。所有关于文件的信息都按以下结构存储在数据库中

  1. 相册 table 有 ID 和名称
  2. 照片 table 有一个照片列表,每张都知道它属于哪个相册
  3. 还有一个photo_versions。每个 photo_versions 存储照片 table 中对象的 ID。

此逻辑由以下架构表示:

CREATE TABLE albums(`id` int, `name` varchar(255)); 
INSERT INTO albums (id, name) VALUES 
(1, "one"),
(2, "two"),
(3, "three");

CREATE TABLE photos(`id` int, `albums_id` int, `title` varchar(255));
INSERT INTO photos (id, albums_id, title) VALUES 
(1, 1, "a"),
(2, 1, "b"),
(3, 1, "c");

CREATE TABLE photos_versions(`id` int, `photos_id` int, `width` int, `height` int);
INSERT INTO photos_versions (photos_id, width, height) VALUES 
(1, 1000, 800),(1, 800, 600), (1, 600, 400),
(2, 1000, 800), (2, 800, 600), (2, 600, 400),
(3, 1000, 800), (3, 800, 600), (3, 600, 400);

用户界面能够请求特定高度,我正在处理的后端应该return 数据库中最接近的高度。我正在按照应该做的要求工作。首先加入所有这些 tables:

SELECT *
FROM albums a
INNER JOIN photos p ON p.albums_id = a.id
INNER JOIN photos_versions pv ON pv.photos_id = p.id;

结果如下 table:

+------+------+----+-----------+-------+------+-----------+-------+--------+
| id   | name | id | albums_id | title | id   | photos_id | width | height |
+------+------+----+-----------+-------+------+-----------+-------+--------+
|    1 | one  |  1 |         1 | a     | NULL |         1 |  1000 |    800 |
|    1 | one  |  1 |         1 | a     | NULL |         1 |   800 |    600 |
|    1 | one  |  1 |         1 | a     | NULL |         1 |   600 |    400 |
|    1 | one  |  2 |         1 | b     | NULL |         2 |  1000 |    800 |
|    1 | one  |  2 |         1 | b     | NULL |         2 |   800 |    600 |
|    1 | one  |  2 |         1 | b     | NULL |         2 |   600 |    400 |
|    1 | one  |  3 |         1 | c     | NULL |         3 |  1000 |    800 |
|    1 | one  |  3 |         1 | c     | NULL |         3 |   800 |    600 |
|    1 | one  |  3 |         1 | c     | NULL |         3 |   600 |    400 |
+------+------+----+-----------+-------+------+-----------+-------+--------+
9 rows in set (0.00 sec)

现在,我们需要按 photos_id 分组(因为我们希望得到与给定照片最接近的版本)。所以,请求变成了:

SELECT *
FROM albums a
INNER JOIN photos p ON p.albums_id = a.id
INNER JOIN photos_versions pv ON pv.photos_id = p.id
GROUP BY photos_id;

结果如下 table:

+------+------+----+-----------+-------+------+-----------+-------+--------+
| id   | name | id | albums_id | title | id   | photos_id | width | height |
+------+------+----+-----------+-------+------+-----------+-------+--------+
|    1 | one  |  1 |         1 | a     | NULL |         1 |  1000 |    800 |
|    1 | one  |  2 |         1 | b     | NULL |         2 |  1000 |    800 |
|    1 | one  |  3 |         1 | c     | NULL |         3 |  1000 |    800 |
+------+------+------+-----------+-------+------+-----------+-------+--------+
3 rows in set (0.00 sec)

但是,它不一定保留 属性 的行(高度最接近我指定的高度)。我如何 GROUP BY photos_id 并选择最接近高度的那个?

P.S。 SQL Fiddle 附上 - http://sqlfiddle.com/#!9/84f4f/1

这里的一种方法是向您的查询添加一个额外的连接,这将限制每个照片 ID 组具有最接近高度的照片。

SELECT a.*, p.*, pv1.*
FROM albums a
INNER JOIN photos p
    ON p.albums_id = a.id
INNER JOIN photos_versions pv1
    ON pv1.photos_id = p.id
INNER JOIN
(
    SELECT photos_id, MIN(ABS(height - SOME_HEIGHT)) AS diff
    FROM photos_versions
    GROUP BY photos_id
) pv2
    ON pv1.photos_id = pv2.photos_id AND
       MIN(ABS(pv1.height - SOME_HEIGHT)) = pv2.diff

您可以将 SOME_HEIGHT 替换为您从身高搜索中获得的任何值。