我有3张桌子:
actor
| FIELD | TYPE | NULL | KEY | DEFAULT | EXTRA |
|----------|------------------|------|-----|---------|----------------|
| actor_id | int(10) unsigned | NO | PRI | (null) | auto_increment |
| username | varchar(30) | NO | | (null) | |
tag
| FIELD | TYPE | NULL | KEY | DEFAULT | EXTRA |
|--------|------------------|------|-----|---------|----------------|
| tag_id | int(10) unsigned | NO | PRI | (null) | auto_increment |
| title | varchar(40) | NO | | (null) | |
actor_tag_count
| FIELD | TYPE | NULL | KEY | DEFAULT | EXTRA |
|------------------|------------------|------|-----|-------------------|-----------------------------|
| actor_id | int(10) unsigned | NO | PRI | (null) | |
| tag_id | int(10) unsigned | NO | PRI | (null) | |
| clip_count | int(10) unsigned | NO | | (null) | |
| update_timestamp | timestamp | NO | | CURRENT_TIMESTAMP | on update CURRENT_TIMESTAMP |
我想为每个演员获得最常见的5个(最高clip_count
)和最近更新的(最新update_timestamp
)个标签。
我的尝试查询是:
SELECT
`a`.`actor_id`,
`a`.`username`,
GROUP_CONCAT(atc.clip_count) AS `tag_clip_counts`,
GROUP_CONCAT(t.tag_id) AS `tag_ids`,
GROUP_CONCAT(t.title) AS `tag_titles`
FROM
`actor` AS `a`
LEFT JOIN (
SELECT
`atc`.`actor_id`,
`atc`.`tag_id`,
`atc`.`clip_count`
FROM
`actor_tag_count` AS `atc`
INNER JOIN `actor` AS `a` USING (actor_id)
ORDER BY
atc.clip_count DESC,
atc.update_timestamp DESC
LIMIT 5
) AS `atc` USING (actor_id)
LEFT JOIN `tag` AS `t` ON atc.tag_id = t.tag_id
GROUP BY
`a`.`actor_id`
问题是左连接子选择仅计算一次,并且集合中每个结果的标记仅从5个标记的池中获取。
Keanu Reeves的预期GROUP_CONCAT
'd标签标题结果:
comedy, scifi, action, suspense, western
(西方和纪录片都有clip_count
为2,但western
应首先出现,因为它后来有update_timestamp
)
我不确定这是否与任何相关性有关,但我正在执行actor表上的其他联接,但是已针对此问题删除了这些联接。 这个全部1个查询都是非常可取的,但是即使有2个查询,我也不知道如何做到这一点。 1或2查询解决方案赞赏。
答案 0 :(得分:1)
SQLFiddle,在一个非常好的answer的帮助下,关于使用GROUP_CONCAT限制解决方法:
SELECT
`a`.`actor_id`,
`a`.`username`,
SUBSTRING_INDEX(GROUP_CONCAT(atc.clip_count ORDER BY atc.clip_count DESC, atc.update_timestamp DESC), ',', 5) AS `tag_clip_counts`,
SUBSTRING_INDEX(GROUP_CONCAT(t.tag_id ORDER BY atc.clip_count DESC, atc.update_timestamp DESC), ',', 5) AS `tag_ids`,
SUBSTRING_INDEX(GROUP_CONCAT(t.title ORDER BY atc.clip_count DESC, atc.update_timestamp DESC), ',', 5) AS `tag_titles`
FROM
`actor` AS `a`
LEFT JOIN actor_tag_count AS `atc` USING (actor_id)
LEFT JOIN `tag` AS `t` ON atc.tag_id = t.tag_id
GROUP BY
`a`.`actor_id`
答案 1 :(得分:0)
可以通过添加序列号来实现,但在大型表上可能效果不佳。
像这样(未经测试): -
SELECT actor_id,
username,
GROUP_CONCAT(clip_count) AS tag_clip_counts,
GROUP_CONCAT(tag_id) AS tag_ids,
GROUP_CONCAT(title) AS tag_titles
FROM
(
SELECT actor.actor_id,
actor.username,
atc.clip_count,
tag.tag_id,
tag.title,
@aSeq := IF(@aActorId = actor.actor_id, @aSeq, 0) + a AS aSequence,
@aActorId := actor.actor_id
FROM
(
SELECT actor.actor_id,
actor.username,
atc.clip_count,
tag.tag_id,
tag.title
FROM actor
LEFT JOIN actor_tag_count AS atc ON actor.actor_id = atc.actor_id
LEFT JOIN tag ON atc.tag_id = tag.tag_id
ORDER BY actor.actor_id, atc.clip_count DESC, atc.update_timestamp DESC
)
CROSS JOIN (SELECT @aSeq:=0, @aActorId:=0)
)
WHERE aSequence <= 5
GROUP BY actor_id, username
另一种方法是在select语句中使用具有相关子查询的子选择(限制为5),然后使用外部查询来执行组连接。这样的事情(再次没有经过测试)
SELECT
actor_id,
username,
GROUP_CONCAT(clip_count) AS tag_clip_counts,
GROUP_CONCAT(tag_id) AS tag_ids,
GROUP_CONCAT(title) AS tag_titles
FROM
(
SELECT
a.actor_id,
a.username,
(
SELECT
atc.clip_count,
t.tag_id,
t.title
FROM actor_tag_count AS atc ON a.actor_id = atc.actor_id
LEFT JOIN tag t ON atc.tag_id = t.tag_id
ORDER BY atc.clip_count DESC, atc.update_timestamp DESC
LIMIT 5
)
FROM actor a
)
GROUP BY actor_id, username