【问题标题】:Grouping, counts and where分组、计数和位置
【发布时间】:2012-08-11 20:43:59
【问题描述】:

我被难住了,摸不着头脑。它一定很简单,但我没有看到它。

假设我有四个表:

video = id
hastag = id, tag_id, video_id
hasteam = id, team_id, video_id
hasidol = id, idol_id, video_id

此数据集(仅作为示例):

video = (1), (2), (3)
hastag = (1, 1, 1), (2, 1, 2), (3, 2, 3)
hasteam = (1, 1, 1), (2, 1, 3), (3, 2, 2)
hasidol = (1, 1, 3)

这个查询:

SELECT v.id ,
COUNT(vhtag.id),
COUNT(vhteam.id),
COUNT(vhidol.id)
FROM video v
LEFT JOIN hastag vhtag ON vhtag.video_id = v.id
LEFT JOIN hasteam vhteam ON vhteam.video_id = v.id
LEFT JOIN hasidol vhidol ON vhidol.video_id = v.id

WHERE
v.id <> 1
AND
(
  vhtag.tag_id IN (SELECT htt2.tag_id FROM hastag htt2 WHERE video_id = 1)
  OR
  vhteam.team_id IN (SELECT htt3.team_id FROM hasteam htt3 WHERE video_id = 1)
  OR
  vhidol.idol_id IN (SELECT htt4.idol_id FROM hasidol htt4 WHERE video_id = 1)
)
GROUP BY v.id

它为我提供了与 WHERE 子句不对应的“具有”行数。例如,如果视频行只有一个共同的视频 ID 为 1 的团队和一个完全不相关的标签,当它应该说“共同标签”时,它会给我“共同标签计数:1,共同团队计数:1”计数:0(因为它是一个无关标签),普通团队计数:1”。

现在,只要我将查询限制为只有一个“有”表,如下所示:

SELECT v.id ,
COUNT(vhtag.id)
FROM video v
LEFT JOIN hastag vhtag ON vhtag.video_id = v.id

WHERE
v.id <> 1
AND
(
  vhtag.tag_id IN (SELECT htt2.tag_id FROM hastag htt2 WHERE video_id = 1)
)
GROUP BY v.id

然后它确实有效,但问题是当我尝试在查询中放入多个“has”表时。我尝试使用 HAVING,但它无法识别“vhtag.tag_id”列。 我显然在这里做错了什么,任何人都可以帮助我吗?

编辑:

这种作品:

LEFT JOIN hastag vhtag ON vhtag.video_id = v.id AND vhtag.tag_id IN (SELECT htt2.tag_id FROM hastag htt2 WHERE video_id = 1)
LEFT JOIN hasteam vhteam ON vhteam.video_id = v.id AND vhteam.team_id IN (SELECT htt3.team_id FROM hasteam htt3 WHERE video_id = 1)
LEFT JOIN hasidol vhidol ON vhidol.video_id = v.id AND vhidol.idol_id IN (SELECT htt4.idol_id FROM hasidol htt4 WHERE video_id = 1)

我也可以在 Doctrine 中使用它(我很笨,忘记了 WITH)。这是最佳方式吗?

【问题讨论】:

  • 请说出查询的预期结果或在示例数据上指定结果..
  • 抱歉,问题发布后已经编辑了几次。现在应该更清楚了。
  • 请提供所需的结果集。这可能会有所帮助。

标签: mysql sql count group-by where


【解决方案1】:

您遇到的问题是您的联接导致每个团队内部出现交叉联接。

最简单的方法是做count distinct:

SELECT v.id , COUNT(distinct vhtag.id), COUNT(distinct vhteam.id),
       COUNT(distinct vhidol.id)
FROM video v LEFT JOIN
     hastag vhtag
     ON vhtag.video_id = v.id
     LEFT JOIN hasteam vhteam
     ON vhteam.video_id = v.id
     LEFT JOIN hasidol vhidol
     ON vhidol.video_id = v.id 

真正的解决方案是将每个值单独聚合,然后将结果连接在一起。

【讨论】:

  • 实际情况并非如此。抱歉,我知道我可能不擅长解释,但请注意我的查询中有一个“1”,这是作为参数传递的视频 ID。这不仅仅是加入反对 v.id。查看我编辑中的连接以了解我的意思。基本上,它建立了一种关系 - 查找与我正在使用其 ID 的视频共享标签的视频(共享至少一个“拥有”,即它们至少具有三种标签类型之一的至少一个实例)作为参数(在本例中为 1)。
【解决方案2】:

尽量简化查询,例如这样-

SELECT
  v.id,
  COUNT(vhtag.id),
  COUNT(vhteam.id),
  COUNT(vhidol.id)
FROM
  video v
LEFT JOIN (SELECT * FROM hastag WHERE video_id = 1) vhtag
  ON vhtag.video_id = v.id
LEFT JOIN (SELECT * FROM hasteam WHERE video_id = 1) vhteam
  ON vhteam.video_id = v.id
LEFT JOIN (SELECT * FROM hasidol WHERE video_id = 1) vhidol
  ON vhidol.video_id = v.id
WHERE
  v.id <> 1
GROUP BY
  v.id

它给出正确的结果吗?

输出:

+------+-----------------+------------------+------------------+
| id   | COUNT(vhtag.id) | COUNT(vhteam.id) | COUNT(vhidol.id) |
+------+-----------------+------------------+------------------+
|    2 |               0 |                0 |                0 |
|    3 |               0 |                0 |                0 |
+------+-----------------+------------------+------------------+

【讨论】:

  • 不幸的是,这不会返回任何行,而我在编辑中发布的联接确实有效。如果我冒险猜测,可能是因为您的联接基本上重叠了两个条件:video_id = 1 和 video_id = v.id,在这种情况下这将是矛盾的。
猜你喜欢
  • 2016-09-30
  • 2015-04-06
  • 1970-01-01
  • 2020-10-07
  • 1970-01-01
  • 2021-10-13
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多