【问题标题】:SQL query to retrieve all products under some categories in Adjacency List ModelSQL查询检索邻接表模型中某些类别下的所有产品
【发布时间】:2013-09-06 20:21:46
【问题描述】:

我有一个使用邻接列表方法的数据库来处理产品分类,其中一种产品可能在许多类别中找到。看看下面的数据库布局:

cats
id    parent    title           desc
1     0         top             top level
2     1         Electronics
3     2         Gaming
4     2         Computers
5     4         Tablets
6     1         Food
7     3         Xbox

products
id        title         qty
1         ToshibaTV     5
2         I-PAD2        9
3         Laser Pen     24
4         Asus Notebook 5


cats_products
id   product_id   cat_id 
1    2            3
2    2            5
3    1            2
4    3            2
5    4            4 

在上面的示例中,我需要一个 SQL 查询,它能够检索在 Electronics 类别中找到的所有产品以及它的任何级别的任何子类别(例如 Xbox,它不是直接子类别)的电子产品)没有重复出现在 I-PAD2 等多个类别中的产品。

我可以在 PHP 中的应用程序的帮助下做到这一点,但我想知道是否可以只使用 MySQL 中的纯 sql 来做到这一点?

【问题讨论】:

  • 您可能希望查看用于存储类别层次结构的嵌套集模型,然后只需找到该项目所属的所有类别并找到每个 mikehillyer.com/articles/managing-hierarchical-data-in-mysql 的子类别
  • @Mike 这是一个非常好的评论,我认为您应该将其表述为一个答案,这样您就可以因提供合理的资源来处理该问题而获得适当的奖励:)
  • @Mike 教程很好,但是它处理类别产品关系是一对多而不是多对多!
  • @sємsєм 您能否根据您提供的数据样本向我们展示预期结果?

标签: php mysql sql many-to-many


【解决方案1】:

使用邻接列表模型您尝试做的事情相当困难。正如@Mike 所建议的那样,使用嵌套集模型会使这变得容易得多。或者通过你的 php 代码来做会更容易。

但是,假设您知道可能有多少个父子级别(或者您可以假设不会超过 X),您可以尝试这样的事情。如果 MySQL 支持 CTE,这将更容易阅读,但不幸的是,它不支持。在这个例子中,我已经深入了 4 个级别——你可以理解更深入的想法。

SELECT p.Id, p.Title, p.Qty
FROM Products p
   JOIN Cats_Products cp on p.id = cp.product_id
WHERE cp.cat_id IN (
   SELECT c.id
   FROM Cats c
   WHERE c.title = 'Electronics'
   UNION ALL
   SELECT c2.id
   FROM Cats c
      LEFT JOIN Cats c2 ON c.id = c2.parent
   WHERE c.title = 'Electronics'
   UNION ALL
   SELECT c3.id
   FROM Cats c
      LEFT JOIN Cats c2 ON c.id = c2.parent
      LEFT JOIN Cats c3 ON c2.id = c3.parent
   WHERE c.title = 'Electronics'
   UNION ALL
   SELECT c4.id
   FROM Cats c
      LEFT JOIN Cats c2 ON c.id = c2.parent
      LEFT JOIN Cats c3 ON c2.id = c3.parent
      LEFT JOIN Cats c4 ON c3.id = c4.parent
   WHERE c.title = 'Electronics'
)
GROUP BY p.Id, p.Title, p.Qty

这里是SQL Fiddle

祝你好运。

【讨论】:

  • 优秀。在应用程序的帮助下,子类别的限制并不是一个重要的问题——您的完美查询可能会被循环以编写更多级别。但是,您@Mike 认为嵌套集模型在此要求方面要容易得多,所以,您能否通过将其添加到答案中来告诉我如何?事实上,我使用 CakePHP 和 CakePHP 的树行为,如果我决定使用它,它支持嵌套模型,知道嵌套集合模型是如何做到这一点的会很有用吗?非常感谢。
  • 我喜欢这个网站,非常接近我为完全相同的问题而一直在玩弄的 sql。很高兴看到我离基地不远。好答案
【解决方案2】:

这是你问题的第一部分。您能否更详细地解释一下子部分。我想这与猫的父母有关。

试试这个:

SELECT distinct(p.title) 
FROM cats AS c
JOIN cats_products AS cp
ON cp.cat_id = c.id AND c.title = "Electronics"
JOIN products AS p
ON p.id = cp.product_id;

样本数据:

CREATE TABLE cats
    (`id` int, `parent` int, `title` varchar(11), `desc` varchar(9))
;

INSERT INTO cats
    (`id`, `parent`, `title`, `desc`)
VALUES
    (1, 0, 'top', 'top level'),
    (2, 1, 'Electronics', ''),
    (3, 2, 'Gaming', ''),
    (4, 2, 'Computers', ''),
    (5, 4, 'Tablets', ''),
    (6, 1, 'Food', ''),
    (7, 3, 'Xbox', '')
;



CREATE TABLE products
    (`id` int, `title` varchar(13), `qty` int)
;

INSERT INTO products
    (`id`, `title`, `qty`)
VALUES
    (1, 'ToshibaTV', 5),
    (2, 'I-PAD2', 9),
    (3, 'Laser Pen', 24),
    (4, 'Asus Notebook', 5)
;



CREATE TABLE cats_products
    (`id` int, `product_id` int, `cat_id` int)
;

INSERT INTO cats_products
    (`id`, `product_id`, `cat_id`)
VALUES
    (1, 2, 3),
    (2, 2, 5),
    (3, 1, 2),
    (4, 3, 2),
    (5, 4, 4)
;

SQL FIDDLE DEMO

编辑第二部分

SELECT distinct(v.title) FROM products AS v
JOIN (
  SELECT Y.product_id FROM cats_products AS Y
    JOIN(
      SELECT distinct(z.id) FROM cats AS Z
        JOIN
          (SELECT c.parent
           FROM cats AS c
           JOIN cats_products AS cp
           ON cp.cat_id = c.id 
           AND c.title = "Electronics") AS X
         ON x.parent = z.parent) AS W
    ON W.id = Y.cat_id) AS u
ON u.product_id = v.id
;

样本数据

CREATE TABLE cats
    (`id` int, `parent` int, `title` varchar(11), `desc` varchar(9))
;

INSERT INTO cats
    (`id`, `parent`, `title`, `desc`)
VALUES
    (1, 0, 'top', 'top level'),
    (2, 1, 'Electronics', ''),
    (3, 2, 'Gaming', ''),
    (4, 2, 'Computers', ''),
    (5, 4, 'Tablets', ''),
    (6, 1, 'Food', ''),
    (7, 3, 'Xbox', '')
;



CREATE TABLE products
    (`id` int, `title` varchar(13), `qty` int)
;

INSERT INTO products
    (`id`, `title`, `qty`)
VALUES
    (1, 'ToshibaTV', 5),
    (2, 'I-PAD2', 9),
    (3, 'Laser Pen', 24),
    (4, 'Asus Notebook', 5),
    (5, 'French Fries', 50)
;



CREATE TABLE cats_products
    (`id` int, `product_id` int, `cat_id` int)
;

INSERT INTO cats_products
    (`id`, `product_id`, `cat_id`)
VALUES
    (1, 2, 3),
    (2, 2, 5),
    (3, 1, 2),
    (4, 3, 2),
    (5, 4, 4),
    (5, 5, 6)

;

这是我对您问题的解释:每个类别都有一个父类别,您希望选择具有相同父类别的所有其他类别。更具体地说,所有具有相同父类别的产品。 SQL FIDDLE DEMO

【讨论】:

  • 我认为这不是 OP 打算做的——它只搜索顶级,而 OP 想要搜索顶级和所有子级别(使用起来相当困难邻接表模型。)祝你好运。
  • @sgeddes 如果是这种情况,他可以忽略我的回答并接受你的回答。
猜你喜欢
  • 2023-03-13
  • 1970-01-01
  • 2021-02-21
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-06-20
相关资源
最近更新 更多