mySQL带来的结果不应该是

mySQL带来的结果不应该是,mysql,left-join,coalesce,Mysql,Left Join,Coalesce,我有一个表格,里面装满了用户编写的品尝笔记,还有一个表格保存了其他用户对每个品尝笔记的评分 查询由您尚未评级的其他用户编写的所有笔记,如下所示: SELECT tastingNotes.userID, tastingNotes.beerID, tastingNotes.noteID, tastingNotes.note, COALESCE(sum(tasteNoteRate.Score), 0) as count, CASE WHEN tasteNoteRate.userVoting = 1

我有一个表格,里面装满了用户编写的品尝笔记,还有一个表格保存了其他用户对每个品尝笔记的评分

查询由您尚未评级的其他用户编写的所有笔记,如下所示:

SELECT tastingNotes.userID, tastingNotes.beerID, tastingNotes.noteID, tastingNotes.note, COALESCE(sum(tasteNoteRate.Score), 0) as count, 
CASE 
WHEN tasteNoteRate.userVoting = 1162 THEN 1 
ELSE 0
END AS userScored
FROM  tastingNotes
left join tasteNoteRate on tastingNotes.noteID = tasteNoteRate.noteID
WHERE tastingNotes.userID != 1162 
Group BY tastingNotes.noteID
HAVING userScored < 1
ORDER BY count, userScored

但是,每次运行上述查询时,仍然会返回它。…

更改为内部联接

tastenotenate表与tastingNotes保持连接,这意味着返回完整的tastingNotes表(与where匹配),然后通过tastenote表中的匹配字段进行扩展。如果不满足TasteNotate,则不会阻止tastingNotes返回匹配的字段。内部连接将采用交叉点

有关联接类型的详细说明,请参见此处:

确保在这两个表中都创建一个noteID索引,否则这个查询和用例将很快爆炸

注意:根据您编写的用例,我仍然不能100%确定您是否希望加入noteID。事实上,它将尝试为您提供一个关于所有注释的联接表,并为所有用户提供所有评分。我认为情况是这样的…END会干扰查询优化器,并将其转换为完全扫描+连接。为什么不在
的where
…“
和tastenote.userVoting=1162
”中添加另一个子句呢

如果这些表不是看起来的1-1(给定sum()和“groupby”),那么当前查询将面临一个爆炸性的问题。如果每个注释可以有10个不同的评级,并且有10个注释,那么就有100个候选结果行。如果它增长到1000和1000,您将很快耗尽内存。删除几个用户ID没有投票的行会从最终1000000+中删除10行,然后对它们进行汇总和分组

另一种方法是反转左连接:

选择…,求和()。。。来自Tastenolate。。。使用(noteID)左连接tastingNotes,其中userID!=xxx按noteID分组
,这样您只能获得其他用户笔记的tastingNotes信息

也许这会有帮助,也许不会,但是的,模式和特定用例/示例数据会有所帮助


有了这种“评级”,有时候最好是维护一个投票总数汇总表,只跟踪用户已经投票的项目。e、 g.不要在select查询中将它们全部相加。相反,在重复密钥更新时的插入中对其进行汇总(total=total+1);至少在一些用户排名表中我就是这样处理这个问题的。它们长得如此之快。

变为内部连接

tastenotenate表与tastingNotes保持连接,这意味着返回完整的tastingNotes表(与where匹配),然后通过tastenote表中的匹配字段进行扩展。如果不满足TasteNotate,则不会阻止tastingNotes返回匹配的字段。内部连接将采用交叉点

有关联接类型的详细说明,请参见此处:

确保在这两个表中都创建一个noteID索引,否则这个查询和用例将很快爆炸

注意:根据您编写的用例,我仍然不能100%确定您是否希望加入noteID。事实上,它将尝试为您提供一个关于所有注释的联接表,并为所有用户提供所有评分。我认为情况是这样的…END会干扰查询优化器,并将其转换为完全扫描+连接。为什么不在
的where
…“
和tastenote.userVoting=1162
”中添加另一个子句呢

如果这些表不是看起来的1-1(给定sum()和“groupby”),那么当前查询将面临一个爆炸性的问题。如果每个注释可以有10个不同的评级,并且有10个注释,那么就有100个候选结果行。如果它增长到1000和1000,您将很快耗尽内存。删除几个用户ID没有投票的行会从最终1000000+中删除10行,然后对它们进行汇总和分组

另一种方法是反转左连接:

选择…,求和()。。。来自Tastenolate。。。使用(noteID)左连接tastingNotes,其中userID!=xxx按noteID分组
,这样您只能获得其他用户笔记的tastingNotes信息

也许这会有帮助,也许不会,但是的,模式和特定用例/示例数据会有所帮助


有了这种“评级”,有时候最好是维护一个投票总数汇总表,只跟踪用户已经投票的项目。e、 g.不要在select查询中将它们全部相加。相反,在重复密钥更新时的插入中对其进行汇总(total=total+1);至少在一些用户排名表中我就是这样处理这个问题的。MySQL允许您以一种非常特殊的方式使用分组方式,而无需抱怨,请参阅:

如果仅禁用了_FULL _GROUP _BY,则GROUP BY标准SQL使用的MySQL扩展允许select list、HAVING condition或ORDER BY list引用未聚合的列,即使这些列在功能上不依赖于GROUP BY列。[…]在这种情况下,服务器可以从每个组中自由选择任何值,因此,除非它们相同,否则选择的值是不确定的,这可能不是您想要的

这种行为是MySQL 5.7之前的默认行为

在您的案例中,这意味着,如果某个特定的
noteID
tastenotenate
中有多行,那么如果其他人已经为该注释投票,
userScored
,它正在使用
tastenotenate.userVoting
,而没有聚合函数,将基于随机行,很可能是错误的行

你可以
noteID | userVoting | score
  113       1162        0
select ..., 
   max(CASE 
   WHEN tasteNoteRate.userVoting = 1162 THEN 1 
   ELSE 0
   END) AS userScored
from ...
select ..., 
   coalesce(max(tasteNoteRate.userVoting = 1162),0) AS userScored
from ...
select tastingNotes.*, 
       coalesce(rates.count, 0) as count, 
       coalesce(rates.userScored,0) as userScored
from tastingNotes
left join (
  select tasteNoteRate.noteID,
         sum(tasteNoteRate.Score) as count,
         max(tasteNoteRate.userVoting = 1162) as userScored
  from tasteNoteRate
  group by tasteNoteRate.noteID
) rates 
on tastingNotes.noteID = rates.noteID and rates.userScored = 0
where tastingNotes.userID != 1162 
order by count;