简体   繁体   English

MySQL查询返回多个值-应该返回一个

[英]mysql query returning more than one value - should return one

I have a website where visitors can create "battles" and upload videos to compete in these battles. 我有一个网站,访客可以创建“战斗”并上传视频以参加这些战斗。

The following mySQL query is trying to retrieve details of every "battle" in a database. 下面的mySQL查询试图检索数据库中每个“战斗”的详细信息。

The problem I have is that if a "battle creator" has uploaded two "videos" to the same battle, a duplicate battle prints out. 我的问题是,如果“战斗创建者”已将两个“视频”上传到同一战斗中,则打印出重复的战斗。

How can I make the query only print out one value for each battle, even if the videos table has two entries under the same battle_id? 即使视频表在相同的Battle_id下有两个条目,我如何使查询仅为每个战斗打印一个值?

Thanks! 谢谢!

SELECT * from Battles, Player, Video 
WHERE (Battles.battle_creator = Player.player_id 
AND Battles.battle_id = Video.battle_id 
AND Video.player_id = Battles.battle_creator) 
ORDER BY Battles.battle_date DESC;

There's no way to get the information you're asking for from a single query once multiple videos have been assigned to a battle by a single user. 将多个视频分配给单个用户进行战斗后,就无法通过单个查询获取您要的信息。

The best way to get all the data for the battle is to separate your query into two subqueries: 获取所有数据的最佳方法是将查询分为两个子查询:

SELECT * from Battles, Player 
WHERE Battles.battle_creator = Player.player_id
ORDER BY Battles.battle_date DESC;

...and then: ...接着:

SELECT * from Video 
ORDER BY Battles.battle_date DESC, Player.player_id;

The first query will give you one row per battle; 第一个查询将为您在每个战斗中排一行; the second will give you all videos for all battles, which you can iterate over. 第二个将为您提供所有战斗的所有视频,您可以对其进行迭代。

From a scaling perspective, you'll do better to avoid JOINs altogether, so the extra work will be well worth it. 从扩展角度看,您最好完全避免JOIN,因此额外的工作将是值得的。

You can either add LIMIT 1 clause to your query to only get first result, or use DISTINCT clause like 您可以在查询中添加LIMIT 1子句以仅获取第一个结果,也可以使用DISTINCT子句,例如

SELECT DISTINCT *
FROM ...

That said, you should not use "SELECT * " when querying for more than one table - use "SELECT table.*" or "SELECT table.field1, table.field2, ..." to be more specific. 也就是说,查询多个表时,请勿使用“ SELECT *”,而应使用“ SELECT table。*”或“ SELECT table.field1,table.field2,...”进行更具体的说明。

You can't do "exactly" that, because your query: 您不能“完全”做到这一点,因为您的查询是:

SELECT * from Battles, Player, Video  ...

is implicitly asking for all the videos . 正在暗中要求所有视频 So you need to ask yourself first, how do I select that one video I want? 因此,您需要首先问自己, 如何选择想要的那个视频?

If you just want one video, whatever, then add LIMIT 1 to the query and be done with that. 如果您只想播放一部视频,则可以在查询中添加LIMIT 1并完成此操作。 ORDER BY video_date ASC or DESC before the LIMIT to retrieve the earliest or latest video. LIMIT之前按ORDER BY video_date ASC或DESC检索最早或最新的视频。

Otherwise, you have to do something like: 否则,您必须执行以下操作:

SELECT * from Battles
    JOIN Player ON (Battles.battle_creator = Player.player_id)
    JOIN Video  ON (Battles.battle_id = Video.battle_id 
                    AND Video.player_id = Battles.battle_creator)
WHERE Video.video_id = (SELECT MIN(video_id) FROM Video AS Video2 WHERE
               Battles.battle_id = Video2.battle_id 
               AND Video2.player_id = Battles.battle_creator)
ORDER BY Battles.battle_date DESC;

In the example above I used, as "video choice criterion", "the video with smallest video_id". 在上面的示例中,我使用“ video_id最小的视频”作为“视频选择标准”。 You will want to have an index on (Video.video_id), something like 您将需要在(Video.video_id)上建立索引,例如

CREATE INDEX video_ndx ON Video(player_id, battle_id, video_id);

As Ninsuo's comment points out, the proper way to control this is, after your ORDER BY clause, specify LIMIT 1. 正如Ninsuo的评论所指出的那样,控制它的正确方法是在ORDER BY子句之后指定LIMIT 1。

This won't work if you want the entire table, just without duplicates. 如果您想要整个表,而没有重复,这将无法工作。 Consider running some comparison checks on your returned data, or using SELECT DISTINCT. 考虑对返回的数据或使用SELECT DISTINCT进行一些比较检查。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM