大家都知道stackoverflow社区!我已经访问这个网站多年了,这是我的第一篇文章
假设我有一个包含三个表的数据库:
示例:糖果工厂。
在糖果工厂,80种不同的糖果生产了10种糖果袋。
所以:有10种独特的群体类型(袋子),有3种不同的尺寸:(4,5,6);一组是80种独特糖果的组合。
出于这个原因,我创建了一个数据库,(有一些关于哪些糖果组合进入一个组的规则)。
此时我有一个包含40791个独特糖果袋的数据库。
现在我想将一系列糖果与数据库中的所有糖果袋进行比较,结果我想要从数据库中取出的袋子与比较系列中缺少3个或更少的糖果。
-- restore candy status
update candies set selected = 0, blacklisted = 0;
-- set status for candies to be selected
update candies set selected = 1 where name in ('candy01','candy02','candy03','candy04');
select groupId, GroupType, max, count(*) as remainingNum, group_concat(name,', ') as remaining
from groups natural join members natural join candies
where not selected
group by groupid having count(*) <= 3
UNION -- Union with groups which dont have any remaining candies and have a 100% match
select groupid, GroupType, max, 0 as remainingNum, "" as remaining
from groups natural join members natural join candies
where selected
group by groupid having count(*) =groups.size;
以上查询执行此操作。但我想要完成的是在没有结合的情况下做到这一点,因为速度是至关重要的。而且我也是sql的新手,非常渴望学习/看到新的方法。
问候,Rutger
答案 0 :(得分:3)
我不是100%肯定你通过这些查询完成了什么,所以我没有看到一个根本不同的方法。如果您可以包含示例数据来演示您的逻辑,我可以看一下。但是,就简单地组合你的两个查询而言,我可以做到这一点。首先要注意一点,但是......
SQL被编译到查询计划中。如果每个查询的查询计划与另一个查询的显着不同,将它们组合到单个查询中可能是个坏主意。您可能最终得到的是一个适用于这两种情况的单一计划,但对两者都不是很有效。一个糟糕的计划可能比两个好计划更糟糕=&gt;更短,更紧凑的代码并不总能提供更快的代码。
您可以将selected
放入GROUP BY
而不是WHERE
条款中;您有两个UNIONed
个查询这一事实表明您已将它们视为两个独立的组。
然后,您的查询之间的唯一区别是count(*)
上的过滤器,您可以使用CASE WHEN
语句来容纳...
SELECT
groups.groupID,
groups.GroupType,
groups.max,
CASE WHEN Candies.Selected = 0 THEN count(*) ELSE 0 END as remainingNum,
CASE WHEN Candies.Selected = 0 THEN group_concat(candies.name,', ') ELSE '' END as remaining
FROM
groups
INNER JOIN
members
ON members.GroupID = groups.GroupID
INNER JOIN
candies
ON Candies.CandyID = members.CandyID
GROUP BY
Groups.GroupID,
Groups.GroupType,
Groups.max,
Candies.Selected
HAVING
CASE
WHEN Candies.Selected = 0 AND COUNT(*) <= 3 THEN 1
WHEN Candies.Selected = 1 AND COUNT(*) = Groups.Size THEN 1
ELSE 0
END
=
1
布局更改只是因为出于维护原因我不同意使用NATURAL JOIN。它们是初始构建的捷径,也是后期开发中的潜在灾难。但这是一个不同的问题,如果您愿意,可以在线阅读。
答案 1 :(得分:0)
在进行选择时不要更新数据库,第一次更新update candies set selected = 0, blacklisted = 0;
将应用于整个表,并重写每条记录。您应该尝试不使用selected
并将联盟更改为UNION ALL。除此之外,您还尝试使用内部联接而不是自然联接(但我不知道您对成员的糖果架构)
select groupId, GroupType, max, count(*) as remainingNum, group_concat(name,', ') as remaining
from groups
inner join members on members.groupid = groups.groupid
inner join candies on candies.candyid = member.candyid
where name NOT in ('candy01','candy02','candy03','candy04')
group by groups.groupid
having count(*) <= 3
UNION ALL -- Union with groups which dont have any remaining candies and have a 100% match
select groupid, GroupType, max, 0 as remainingNum, "" as remaining
from groups
inner join members on members.groupid = groups.groupid
inner join candies on candies.candyid = member.candyid
where name in ('candy01','candy02','candy03','candy04')
group by groupid
having count(*) = groups.size;
这至少应该比在查询表中更新表中的所有记录更好。