Mysql Sql:选择包含一组特定项目的所有篮子

Mysql Sql:选择包含一组特定项目的所有篮子,mysql,sql,relational-division,Mysql,Sql,Relational Division,艾迪有装满物品的篮子。每个项目可以属于任意数量的篮子,也可以不属于任何篮子 表示它的Sql架构如下所示: tbl_basket - basketId tbl_item - itemId tbl_basket_item - pkId - basketId - itemId 问题:如何选择包含特定项目集的所有篮子 更新。需要所有物品的篮子。否则这将是一项很容易解决的任务 更新B.已经实现了以下解决方案,包括PHP中的SQL生成: SELECT basketId FROM tbl_baske

艾迪有装满物品的篮子。每个项目可以属于任意数量的篮子,也可以不属于任何篮子

表示它的Sql架构如下所示:

tbl_basket
- basketId

tbl_item
- itemId

tbl_basket_item
- pkId
- basketId
- itemId
问题:如何选择包含特定项目集的所有篮子

更新。需要所有物品的篮子。否则这将是一项很容易解决的任务

更新B.已经实现了以下解决方案,包括PHP中的SQL生成:

SELECT basketId
FROM   tbl_basket
JOIN   (SELECT basketId FROM tbl_basket_item WHERE itemId = 1  ) AS t0 USING(basketId)
JOIN   (SELECT basketId FROM tbl_basket_item WHERE itemId = 15 ) AS t1 USING(basketId)
JOIN   (SELECT basketId FROM tbl_basket_item WHERE itemId = 488) AS t2 USING(basketId)
其中连接数等于项目数

除非几乎每个篮子里都包含了一些物品,否则效果很好。然后性能急剧下降

更新B+。应用启发式解决性能问题。首先,选择每个项目的频率。如果超过某个阈值,则不将其包括在联接中,并且:

  • 在PHP中应用后期过滤
  • 或者只是不按特定的itemId应用过滤器,在合理的时间内为用户提供大致的结果
更新B++。目前的问题在MySQL中似乎没有很好的解决方案。这一点提出了一个问题和一个解决方案:

  • (问题)PostgreSQL是否有一些高级索引技术,可以在不进行完全扫描的情况下解决此问题
  • (解决方案)似乎可以在Redis中使用sets和SINTER命令很好地解决这个问题,以获得一个交点

我认为最好的方法是创建一个包含所需项集的临时表(将项ID作为参数或沿着这些行的某个内容的过程),然后左键连接,将上面所有的表连接在一起


如果对于给定的篮子ID,在左连接的右侧没有空值,则篮子包含所有需要的项目

如果要提供项目列表,请在以下查询中编辑id1、id2等:

select distinct t.basketId
from tbl_basket_item as t
where t.itemID in (id1, id2)

将给出包含一组项目的所有篮子。无需联接任何其他表,因为您的需求不需要它们。

最简单的解决方案是使用
HAVING
子句

-- the table definitions
CREATE TABLE basket ( basketid INTEGER NOT NULL PRIMARY KEY);
CREATE TABLE item ( itemid INTEGER NOT NULL PRIMARY KEY);
CREATE TABLE basket_item
        ( basketid INTEGER NOT NULL REFERENCES basket (basketid)
        , itemid INTEGER NOT NULL REFERENCES item (itemid)
        , PRIMARY KEY (basketid, itemid)
        );

-- the query
SELECT * FROM basket b
WHERE NOT EXISTS (
        SELECT * FROM item i
        WHERE i.itemid IN (1,15,488)
        AND NOT EXISTS (
                SELECT * FROM basket_item bi
                WHERE bi.basketid = b.basketid
                AND bi.itemid = i.itemid
                )
        );
SELECT basketId
FROM   tbl_basket
WHERE itemId IN (1,15,488)
HAVING Count(DISTINCT itemId) = 3 --DISTINCT in case we have duplicate items in a basket
GROUP BY basketId

如何
选择(不同的,如果需要)tb.*从tbl_basket_item tbi在tbi上加入tbl_basket tb.basketId在tbi上加入tbl_item ti.itemID=ti.itemID,其中tbi.itemID IN(1,2,3…)
?使用IN还将返回只包含所需项目一部分的篮子。您正在使用哪些DBMS?博士后?甲骨文?@jarlh,一点也不)只是在背后添加了一些故事,不让人们对商业内容感到厌烦。这个问题已经得到了不止一次的回答。请看其他答案。[我添加了标记,因此它们应该显示在右侧的
相关部分-->>]例如:使用in还将返回只包含所需项目一部分的篮子。我不认为这是OP要求的。没有单独的模式将项目与篮子联系起来,这是您对问题的解释。我相信OP会证明这一点。在任何情况下,我都可以修改OP wants.PS-如果您希望篮子只包含这些项目,请执行完全联接,并确保给定BasketId的任何一侧都没有空值,这肯定是一个解决方案。我只是希望能找到一些更简单、更像现成的方法来应对这种情况,这对我来说似乎是一项普通的任务。我能想到的唯一其他解决方案是字符串连接——性能下降可能太高。我会试试看,但不确定它对重表的性能是否良好。@DenisKulagin,这将取决于您的数据,但肯定它的性能应该比问题中的查询更好。至少在大多数情况下是这样。