ker*_*lin 9 ruby mysql sql algorithm ruby-on-rails
我有一个名为Buyable的基于STI的模型,有两个模型Basket和Item.这里可购买的关注属性是:
篮子和物品之间存在亲子关系.对于篮子,parent_id总是为零,但是通过引用唯一的篮子ID,项目可以属于篮子.因此,篮子有很多物品,而物品属于一个篮子.
我需要一个篮子模型的方法:
如果表中有任何其他具有相同数量和类型的项目的篮子,则返回true.当项目共享相同的shop_week_id和location_id时,它们被认为是相同的类型.
例如:
给出一个篮子(uid = 7)有2个项目:
项目#1
项目#2
如果表中有任何其他篮子包含正好2个项目,则返回true,其中一个项目具有shop_week_id = 13且location_id = 103,另一个项目具有shop_week_id = 13和location_id = 204.否则返回false.
你会如何解决这个问题?这是不言而喻的,但我正在寻找一个非常有效的解决方案.
为了澄清我的查询,以及对“可购买”表的表列的描述有些模糊,“Parent_ID”是有问题的篮子。“Shop_Week_ID”是要比较的篮子的考虑因素...不要比较第 1 周到第 2 周到第 3 周的篮子。#ID 列似乎是表中的连续 ID,但不是实际 ID要比较的项目的... Location_ID 似乎是常见的“项目”。在该场景中,假设有一个购物车,Location_ID = 103 =“计算机”,Location_ID = 204 =“电视”(仅用于我对数据的解释)。如果这是不正确的,除了原始海报显示一系列数据之外,可能还需要进行细微调整,以显示适当的相关性。
所以,现在,开始我的查询..我正在执行 STRAIGHT_JOIN,以便它按照我列出的顺序连接。
别名“MainBasket”的第一个查询专门用于查询一次有问题的购物篮中有多少商品,因此不需要为每个可能的篮子匹配而重新加入/再次查询。没有“ON”子句,因为这将是单个记录,因此没有笛卡尔影响,因为我希望将此 COUNT(*) 值应用于最终结果中的每个记录。
下一个查询是查找一个不同的其他篮子,其中与相关父项在同一周内至少有一个“Location_ID”(商品)...这可能会导致其他篮子有 1 个、与该篮子相同或更多的条目。但是,如果有 100 个篮子,但只有 18 个篮子至少有 1 个条目与原始篮子中的 1 个项目相匹配,则您只是显着减少了进行最终比较的篮子数量(SameWeekSimilar 别名结果)。
最后是再次连接到可购买表,但基于 SameWeekSimilar 的连接,但仅针对具有接近匹配的每个“其他”篮子...没有特定项目,仅按篮子。该查询用于获取同一周已通过资格预审的 SameWeekSimilar,以及相关原始购物篮中的至少一件匹配商品,但特别排除原始购物篮,因此它不会与自身进行比较。
通过基于 SameWeekSimilar.NextBasket 在外部级别进行分组,我们可以获得该篮子的实际项目数。由于对 MainBasket 进行了简单的笛卡尔连接,我们只需获取原始计数。
最后是 HAVING 子句。由于这是在“COUNT(*)”之后应用的,因此我们知道“其他”篮子中有多少商品,以及“主”篮子中有多少商品。因此,HAVING 子句仅包括计数相同的子句。
如果您想测试以确保我所描述的内容,请针对您的表运行此命令,但不要包含 HAVING 子句。您将看到哪些是所有可能的...然后重新添加 HAVING 子句并查看哪些确实匹配相同的计数...
select STRAIGHT_JOIN
SameWeekSimilar.NextBasket,
count(*) NextBasketCount,
MainBasket.OrigCount
from
( select count(*) OrigCount
from Buyable B1
where B1.Parent_ID = 7 ) MainBasket
JOIN
( select DISTINCT
B2.Parent_ID as NextBasket
from
Buyable B1
JOIN Buyable B2
ON B1.Parent_ID != B2.Parent_ID
AND B1.Shop_Week_ID = B2.Shop_Week_ID
AND B1.Location_ID = B2.Location_ID
where
B1.Parent_ID = 7 ) SameWeekSimilar
Join Buyable B1
on SameWeekSimilar.NextBasket = B1.Parent_ID
group by
SameWeekSimilar.NextBasket
having
MainBasket.OrigCount = NextBasketCount
Run Code Online (Sandbox Code Playgroud)