查找涉及STI和父子关系的"重复"记录的解决方案

ker*_*lin 9 ruby mysql sql algorithm ruby-on-rails

我有一个名为Buyable的基于STI的模型,有两个模型Basket和Item.这里可购买的关注属性是:

  • shop_week_id
  • LOCATION_ID
  • PARENT_ID

篮子和物品之间存在亲子关系.对于篮子,parent_id总是为零,但是通过引用唯一的篮子ID,项目可以属于篮子.因此,篮子有很多物品,而物品属于一个篮子.

我需要一个篮子模型的方法:

如果表中有任何其他具有相同数量和类型的项目的篮子,则返回true.当项目共享相同的shop_week_id和location_id时,它们被认为是相同的类型.

例如:

给出一个篮子(uid = 7)有2个项目:

项目#1

  • id = 3
  • shop_week_id = 13
  • location_id = 103
  • parent_id = 7

项目#2

  • id = 4
  • shop_week_id = 13
  • location_id = 204
  • parent_id = 7

如果表中有任何其他篮子包含正好2个项目,则返回true,其中一个项目具有shop_week_id = 13且location_id = 103,另一个项目具有shop_week_id = 13和location_id = 204.否则返回false.

你会如何解决这个问题?这是不言而喻的,但我正在寻找一个非常有效的解决方案.

DRa*_*app 0

为了澄清我的查询,以及对“可购买”表的表列的描述有些模糊,“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)