Mysql “寻找”的解决方案;“重复”;涉及性传播感染和亲子关系的记录

Mysql “寻找”的解决方案;“重复”;涉及性传播感染和亲子关系的记录,mysql,sql,ruby-on-rails,ruby,algorithm,Mysql,Sql,Ruby On Rails,Ruby,Algorithm,我有一个基于STI的模型叫Buyable,有两个模型,一个是篮子,一个是物品。此处可购买产品的相关属性包括: 购物周 位置标识 家长id 篮子和物品之间存在父子关系。篮子的父项id始终为零,但通过引用唯一的篮子id,一个项目可以属于篮子。因此篮子中有许多项目,而一个项目属于篮子 我需要一个关于篮子模型的方法: 如果表中有任何其他篮子具有相同数量和类型的项目,则返回true或false。当商品共享同一店铺标识和地点标识时,它们被视为同一类型 例如: 给定一个篮子(uid=7),其中包含两项:

我有一个基于STI的模型叫Buyable,有两个模型,一个是篮子,一个是物品。此处可购买产品的相关属性包括:

  • 购物周
  • 位置标识
  • 家长id
篮子和物品之间存在父子关系。篮子的父项id始终为零,但通过引用唯一的篮子id,一个项目可以属于篮子。因此篮子中有许多项目,而一个项目属于篮子

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

如果表中有任何其他篮子具有相同数量和类型的项目,则返回true或false。当商品共享同一店铺标识和地点标识时,它们被视为同一类型

例如:

给定一个篮子(uid=7),其中包含两项:

项目#1

  • id=3
  • 店铺\周\ id=13
  • 位置_id=103
  • 家长id=7
项目#2

  • id=4
  • 店铺\周\ id=13
  • 位置_id=204
  • 家长id=7
如果表中有任何其他篮子正好包含2个项目,则返回true,其中一个项目的店铺周id=13,位置周id=103,另一个项目的店铺周id=13,位置周id=204。否则返回false


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

下面的SQL似乎可以做到这一点

big_query = "
  SELECT EXISTS (
    SELECT 1
    FROM buyables b1
      JOIN buyables b2
        ON b1.shop_week_id = b2.shop_week_id
        AND b1.location_id = b2.location_id
    WHERE
      b1.parent_id != %1$d
      AND b2.parent_id = %1$d
      AND b1.type = 'Item'
      AND b2.type = 'Item'
    GROUP BY b1.parent_id
    HAVING COUNT(*) = ( SELECT COUNT(*) FROM buyables WHERE parent_id = %1$d AND type = 'Item' )
  )
"
使用ActiveRecord,您可以使用以下方法获得此结果:

class Basket

我对性能不是很确定,但是为了澄清我的疑问,以及对“buyable”表的表列的模糊描述,“Parent_ID”就是问题所在。“购物周ID”是比较购物篮的考虑因素。。。不要将第1周、第2周和第3周的篮子进行比较。#ID列似乎是表中的顺序ID,但不是要比较的项的实际ID。。。位置ID似乎是常见的“项目”。在这个场景中,假设一辆购物车,Location\u ID=103=“Computer”,Location\u ID=204=“Television”(仅用于我对数据的解释)。如果这是不正确的,可能需要轻微的调整,除了原来的海报显示了说。。。一打数据项以显示适当的相关性

那么,现在,我来回答我的问题。。我正在做一个直接的连接,所以它按照我列出的顺序连接

别名“mainbarket”的第一个查询专门用于一次查询有问题的购物篮中有多少项,因此不需要重新加入/查询每个可能匹配的购物篮。没有“ON”子句,因为这将是一条记录,因此没有笛卡尔影响,因为我希望此COUNT(*)值应用于最终结果中的每个记录

下一个查询是查找一个不同的其他篮子,其中至少有一个“Location\u ID”(项)与所讨论的父项在同一周内。。。这可能会导致其他篮子的条目数与篮子的条目数相同或更多。但是,如果有100个篮子,但只有18个篮子至少有1个条目与原始篮子中的1个条目相匹配,那么您就大大减少了要进行最终比较的篮子数量(SameWeekResult)

最后是再次加入buyable表,但基于SameWekSimular的加入,但仅在每个“其他”篮子上有一个接近的匹配。。。没有具体的项目,只是篮子。用于获取SameWekSimular的查询已在同一周进行了资格预审,并且至少有一个匹配项来自所讨论的原始篮子,但明确排除了原始篮子,因此它不会与自身进行比较

通过基于sameweeksimilor.NextBasket在外部级别进行分组,我们可以获得该篮子的实际项目数。由于一个简单的笛卡尔连接到主篮子,我们只需要获取原始计数

最后,HAVING子句。由于这是在“计数(*)之后应用的,因此我们知道“其他”篮子中有多少项目,以及“主”篮子中有多少项目。因此,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

如果你想使这个效率尽可能的高,你应该考虑创建一个散列,它将篮子内容编码为一个字符串或BLB,添加一个包含哈希的新列(它将需要每次更新筐内容时被应用程序或使用触发器更新),并比较散列值以确定可能的相等性。然后您可能需要执行进一步的比较(如上所述),以便


你应该用什么来做散列呢?如果您知道篮子的大小是有限的,并且所讨论的ID是有界整数,那么您应该能够散列到一个本身足以测试相等性的字符串。例如,您可以对每个店铺和地点进行base64编码,使用不在base64中的分隔符(如“|”)连接,然后与其他购物篮项目连接。在新的散列键上建立索引,比较会很快。

SELECT存在(从…
中选择1可能更好。@muistooshort您是正确的,我已经更新了答案。顺便说一句,我刚刚注意到,如果项目可以重复,这可能会返回一个假阳性。如果这是一个问题,可能需要另一个子查询。当我尝试运行您的查询时,我得到一个语法错误:。我自己从未见过%1$d语法,所以不确定它是什么ying to do.@keruilin
%1$d
是篮子id的占位符(请参阅)。
%d
表示整数,
1$
表示“使用第一个参数”。Cou
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