每个关系选择前 N 个项目,每个项目一行

Posted

技术标签:

【中文标题】每个关系选择前 N 个项目,每个项目一行【英文标题】:Select first N items per relationship, one row per item 【发布时间】:2016-11-25 11:04:19 【问题描述】:

假设我有以下架构:

艺术家:

    +------------+------------------+------+-----+---------+----------------+
    | Field      | Type             | Null | Key | Default | Extra                  |
    +------------+------------------+------+-----+---------+----------------+
    | id         | int(10) unsigned | NO   | PRI | NULL    | auto_increment |                   |
    | name       | varchar(255)     | YES  | UNI | NULL    |                |
    +------------+------------------+------+-----+---------+----------------+

事件:

+------------+------------------+------+-----+---------+----------------+
| Field      | Type             | Null | Key | Default | Extra              |
+------------+------------------+------+-----+---------+----------------+
| id         | int(10) unsigned | NO   | PRI | NULL    | auto_increment     |
| date       | timestamp        | YES  |     | NULL    |                |
| artist_id  | int(11)          | YES  |     | NULL    |                |
| venue_id   | int(11)          | YES  |     | NULL    |                |
+------------+------------------+------+-----+---------+----------------+

资产:

+---------------------+------------------+------+-----+---------+----------------+
| Field               | Type             | Null | Key | Default | Extra          |
+---------------------+------------------+------+-----+---------+----------------+
| id                  | int(10) unsigned | NO   | PRI | NULL    | a
| event_id            | int(11)          | YES  |     | NULL    |                 
| source_asset_title  | varchar(255)     | YES  |     | NULL    |                |
| source_created_time | timestamp        | YES  |     | NULL    |                |

而且我想要给定艺术家 ID 的每个事件的 4 个资产的结果集,按事件日期排序,例如:

+----------+----------+------------------------------------------------------------------------------------------------------------------------+---------------------+---------------------+
| event_id | asset_id | source_asset_title                                                                                                     | event_date          | date                |
+----------+----------+------------------------------------------------------------------------------------------------------------------------+---------------------+---------------------+
|        1 |     2089 | aba                                                                                                                       | 2015-12-03 07:00:00 | 2015-12-03 07:00:00 |
|        1 |     2101 | abb                                                                                                                        | 2015-12-03 07:00:00  | 2011-04-07 15:30:00 |
|        1 |     2102 | abc                                                                                                                    | 2015-12-03 07:00:00  | 2011-05-22 16:00:00 |
|        1 |     2107 | abd                                                                                                                     | 2015-12-03 07:00:00  | 2011-06-11 15:00:00 |
|        2 |     2109 | abe                                                                                                                     | 2011-07-18 15:00:00  | 2011-07-18 15:00:00 |
|        2 |     2113 | abf                                                                                                                    | 2011-07-18 15:00:00  | 2011-07-24 15:30:00 |
|        2 |     2115 | abg                                                                                                                    | 2011-07-18 15:00:00  | 2011-08-25 16:00:00 |
|        2 |     2123 | abh                                                                                                                    | 2011-07-18 15:00:00  | 2011-08-28 16:00:00 |
|        3 |     2126 | abi                                                                                                                    | 2011-09-01 16:00:00  | 2011-09-01 16:00:00 |
|        3 |     2129 | abj                                                                                                                    | 2011-09-01 16:00:00  | 2011-09-10 16:00:00 |
|        3 |     2135 | abk                                                                                                                    | 2011-09-01 16:00:00  | 2011-10-14 16:00:00 |
|        3 |     2147 | abl                                                                                                                    | 2011-09-01 16:00:00  | 2011-10-22 16:00:00 |

如果每个事件没有一个子查询,我怎么能做到这一点?

我相信这里的架构和结果集与 StackExchange 上的其他问题有很大不同,因此适合提出新问题。

【问题讨论】:

你能提供一个转储或 sqlfiddle,所以我们有一些数据可以玩吗? 你可以使用 GROUP_CONCAT 和 ***.com/a/23608554/308851 @chx 谢谢!我相信 GROUP_CONCAT 会将资产表的所有值作为字符串放入单个结果行中,这与我希望获得的输出不匹配。 (最终目标是返回描述资产的 json)。 似乎一种潜在的替代方法是使用 GROUP_CONCAT 和 CONCAT 明确地组装一个 JSON 对象,其中包含资产表中的每个字段作为结果集的一部分,类似于@chx 的建议:@ 987654322@ 当然,那么您将面临需要增加 GROUP_CONCAT 长度限制的风险:***.com/questions/2567000/…。 【参考方案1】:

不,没有子查询就不可能达到指定的结果集。作为替代方案,请考虑 GROUP_CONCAT,尽管您可能必须增加 mysql 的 group_concat_max_len 的大小以包含您希望描述的所有列。这可能是一个好主意,也可能不是一个好主意。

【讨论】:

【参考方案2】:

这是artist.id=1 的SQL,按events.date 从新到旧排序

SELECT
  events.id as event_id,
  assets.id as asset_id,
  source_asset_title
FROM assets
INNER JOIN events ON events.id = assets.event_id
INNER JOIN artists ON artists.id = events.artist_id
WHERE artists.id = 1
ORDER BY events.date DESC

【讨论】:

谢谢,但这并没有考虑到“每个事件 4 个资产”的限制,我认为这是问题中具有挑战性的部分。此查询将为每个资产显示一行。 但是等待其他答案 我同意@ColdShine - 连接并不能真正发挥作用,让您限制结果。可以在join的ON语句中使用WHERE条件,但不能这样排序和限制。

以上是关于每个关系选择前 N 个项目,每个项目一行的主要内容,如果未能解决你的问题,请参考以下文章

项目开发第一步

如何在项目管理中建立起良好的团队协作关系

如何从 List<T> 中获取每个第 n 个项目?

有没有办法进一步优化 Python 的 heapq.nlargest 以选择前 N 个项目?

如何选择每个类别最新的四个项目?

如何选择每个类别最新的四个项目?