简体   繁体   English

MySQL查询选择孩子

[英]mySQL query for selecting children

I am not sure if this is possible in mySQL. 我不确定在MySQL中是否可行。 Here are my tables:- 这是我的桌子:

Categories table: 分类表:

  • id ID
  • name 名称
  • parent_id (which points to Categories.id) parent_id(指向Categories.id)

I use the above table to map all the categories and sub-categories. 我使用上表来映射所有类别和子类别。

Products table: 产品表:

  • id ID
  • name 名称
  • category_id category_id

The category_id in the Products table points to the sub-category id in which it belongs. “产品”表中的category_id指向它所属的子类别ID。

eg If I have Toys > Educational > ABC where ABC is product, Toys is Category and Educational is sub Category, then ABC will have category_id as 2. 例如,如果我有“玩具”>“教育”>“ ABC”,其中“ ABC”是产品,“玩具”是“类别”,“教育”是“子类别”,那么ABC的category_id为2。

Now the problem is that I want to use a SQL query to display all the products (in all the sub-categories and their sub-categories.. n level) for a particular category. 现在的问题是,我想使用SQL查询来显示特定类别的所有产品(在所有子类别及其子类别中。n级)。

eg: 例如:

select * from categories,products where  category.name = 'Toys' and ....

The above query should display the products from Educational also and all other sub categories and their subcategories. 上面的查询应显示来自Educational以及所有其他子类别及其子类别的产品。

Is this possible using a mySQL query? 使用mySQL查询可能吗? If not what options do I have? 如果没有,我有什么选择? I would like to avoid PHP recursion. 我想避免PHP递归。

Update: Basically I want to display the top 10 products in the main category which I will be doing by adding a hits column to products table. 更新:基本上,我想通过在商品表中添加点击数列来显示主要类别中排名前10的商品。

What I've done in previous projects where I've needed to do the same thing, I added two new columns. 在以前的项目中需要做同样的事情的地方,我添加了两个新列。

  • i_depth: int value of how deep the category is i_depth:类别的深度的int值
  • nvc_breadcrumb: complete path of the category in a breadcrumb type of format nvc_breadcrumb:类别的完整路径,格式为面包屑

And then I added a trigger to the table that houses the category information to do the following (all three updates are in the same trigger)... 然后,我在表中添加了一个触发器,其中包含类别信息,以执行以下操作(所有三个更新都在同一触发器中)...

-- Reset all branches
UPDATE t_org_branches
    SET nvc_breadcrumb = NULL,
    i_depth = NULL

-- Update the root branches first
UPDATE t_org_branches 
    SET nvc_breadcrumb = '/', 
        i_depth = 0 
    WHERE guid_branch_parent_id IS NULL

-- Update the child branches on a loop
WHILE EXISTS (SELECT * FROM t_branches WHERE i_depth IS NULL) 
    UPDATE tobA 
        SET tobA.i_depth = tobB.i_depth + 1, 
            tobA.nvc_breadcrumb = tobB.nvc_breadcrumb + Ltrim(tobA.guid_branch_parent_id) + '/' 
        FROM t_org_branches AS tobA
            INNER JOIN t_org_branches AS tobB ON (tobA.guid_branch_parent_id = tobB.guid_branch_id) 
        WHERE tobB.i_depth >= 0 
            AND tobB.nvc_breadcrumb IS NOT NULL 
            AND tobA.i_depth IS NULL

And then just do a join with your products table on the category ID and do a "LIKE '%/[CATEGORYID]/%' ". 然后只需对类别ID与您的产品表进行联接,然后执行“ LIKE'%/ [CATEGORYID] /%'”。 Keep in mind that this was done in MS SQL, but it should be easy enough to translate into a MySQL version. 请记住,这是在MS SQL中完成的,但是应该足够容易地转换为MySQL版本。

It might just be compatible enough for a cut and paste (after table and column name change). 它可能只足以进行剪切和粘贴(在更改表名和列名之后)。


Expansion of explanation... 扩展说明...

t_categories (as it stands now)... t_categories(目前为止)...

Cat Parent  CategoryName
1   NULL    MyStore
2   1       Electronics
3   1       Clothing
4   1       Books
5   2       Televisions
6   2       Stereos
7   5       Plasma
8   5       LCD

t_categories (after modification)... t_categories(修改后)...

Cat  Parent  CategoryName   Depth   Breadcrumb
1   NULL    MyStore         NULL    NULL    
2   1       Electronics     NULL    NULL
3   1       Clothing        NULL    NULL
4   1       Books           NULL    NULL
5   2       Televisions     NULL    NULL
6   2       Stereos         NULL    NULL
7   5       Plasma          NULL    NULL
8   5       LCD             NULL    NULL

t_categories (after use of the script I gave) t_categories(使用我提供的脚本后)

Cat  Parent  CategoryName   Depth   Breadcrumb
1   NULL    MyStore         0       /   
2   1       Electronics     1       /1/
3   1       Clothing        1       /1/
4   1       Books           1       /1/
5   2       Televisions     2       /1/2/
6   2       Stereos         2       /1/2/
7   5       LCD             3       /1/2/5/
8   7       Samsung         4       /1/2/5/7/

t_products (as you have it now, no modifications)... t_products(您现在拥有的,没有任何修改)...

ID   Cat Name
1   8   Samsung LNT5271F
2   7   LCD TV mount, up to 36"
3   7   LCD TV mount, up to 52"
4   5   HDMI Cable, 6ft

Join categories and products (where categories is C, products is P) 加入类别和产品(类别为C,产品为P)

C.Cat Parent CategoryName   Depth   Breadcrumb  ID   p.Cat  Name
1    NULL   MyStore         0       /           NULL NULL   NULL
2    1      Electronics     1       /1/         NULL NULL   NULL
3    1      Clothing        1       /1/         NULL NULL   NULL
4    1      Books           1       /1/         NULL NULL   NULL
5    2      Televisions     2       /1/2/       4    5      HDMI Cable, 6ft
6    2      Stereos         2       /1/2/       NULL NULL   NULL
7    5      LCD             3       /1/2/5/     2    7      LCD TV mount, up to 36"
7    5      LCD             3       /1/2/5/     3    7      LCD TV mount, up to 52"
8    7      Samsung         4       /1/2/5/7/   1    8      Samsung LNT5271F

Now assuming that the products table was more complete so that there is stuff in each category and no NULLs, you could do a "Breadcrumb LIKE '%/5/%'" to get the last three items of the last table I provided. 现在假设products表比较完整,以便每个类别中都有东西,而没有NULL,那么您可以执行“ Breadcrumb LIKE'%/ 5 /%'”以获取我提供的最后一个表的最后三个项目。 Notice that it includes the direct items and children of the category (like the Samsung tv). 请注意,它包括该类别的直接项目和子项(例如Samsung电视)。 If you want ONLY the specific category items, just do a "c.cat = 5". 如果只需要特定类别的项目,则只需执行“ c.cat = 5”即可。

I think the cleanest way to achieve this would be to use the nested set model . 我认为实现这一目标的最干净的方法是使用嵌套集模型 It's a bit complicated to implement, but powerful to use. 实现起来有点复杂,但使用起来却功能强大。 MySQL has a tutorial named Managing Hierarchical Data in MySQL . MySQL有一个名为“ 在MySQL中管理分层数据”的教程。 One of the big SQL gurus Joe Celko wrote about the same thing here . SQL专家之一乔•塞尔科(Joe Celko)在这里写了同样的事情。 If you need even more information have a look at Troel's links on storing hierarchical data . 如果您需要更多信息,请参阅Troel有关存储分层数据的链接

In my case I would stay away from using a RDBMS to store this kind of data and use a graph database instead, as the data in this case actually is a directed graph. 就我而言,我将避免使用RDBMS存储此类数据,而应使用图数据库,因为在这种情况下,数据实际上是有向图。

Add a column to the Categories table that will contain the complete comma-delimited tree for each group. 在“类别”表中添加一列,其中将包含每个组的完整的逗号分隔树。 Using your example, sub-category Educational would have this as the tree '1,2', where 1 = Toys, 2 = Educational (it includes itself). 以您的示例为例,“教育”子类别将其作为树“ 1,2”,其中1 =玩具,2 =教育(包括自身)。 The next nested level of categories would keep adding to the tree. 类别的下一个嵌套级别将继续添加到树中。

To get all products in a group, you use MySQL's FIND_IN_SET function, like so 要将所有产品归为一组,请使用MySQL的FIND_IN_SET函数,如下所示

SELECT p.ID 
FROM Products p INNER JOIN Categories c ON p.category_ID = c.ID
WHERE FIND_IN_SET(your_category_id, c.tree)

I wouldn't use this method for big tables, as I don't think this query can use an index. 我不会对大表使用此方法,因为我认为此查询无法使用索引。

One way is to maintain a table that contains the ancestor to descendant relationships. 一种方法是维护一个表,该表包含祖先与后代的关系。 You can query this particular table and get the list of all dependents. 您可以查询此特定表并获取所有依赖项的列表。

Assuming MySQL, it'll be difficult to avoid recursion in PHP. 假设使用MySQL,将很难避免PHP中的递归。

Your question is, essentially, how to mimic Oracle's CONNECT BY PRIOR syntax in MySQL. 本质上,您的问题是如何在MySQL中模仿Oracle的CONNECT BY PRIOR语法。 People ask this question repeatedly but it's a feature that's never made it in to MySQL and implementing is via stored procedures probably won't work because (now) stored functions cannot be recursive . 人们反复问这个问题 但这是MySQL从未使用过的功能,通过存储过程实现可能无法正常工作,因为(现在) 存储函数无法递归

Beware of the database kludges offered so far. 谨防到目前为止提供的数据库错误。

The best information so far are the three links from nawroth : 到目前为止,最好的信息是nawroth三个链接

How big is the table Categories? 表格类别有多大? You may need to cache this on the application level and construct the appropriate query: ... where id in (2, 3, 6, 7) 您可能需要在应用程序级别上对此进行缓存并构造适当的查询:...其中(2,3,6,7)中的id

Also, it's best if you fetch categories by id which is their unique ID, indexed and fast as opposed to finding by name. 另外,最好按ID(即其唯一ID)检索类别,并且索引快速,而不是按名称查找。

Bear with me, because I have never done something like this. 忍受我,因为我从未做过这样的事情。

BEGIN
  SET cat = "5";
  SET temp = "";

  WHILE STRCMP(temp, cat) != 0 DO
    SET temp = cat;
    SET cat = SELECT CONCAT_WS(GROUP_CONCAT(id), cat) FROM Categories GROUP BY (parent_id) HAVING FIND_IN_SET(parent_id, cat);
  END LOOP;
END;

SELECT * FROM products WHERE FIND_IN_SET(category_id, cat)

I can almost guarantee the above won't work, but you can see what I'm trying to do. 我几乎可以保证上述方法不会起作用,但是您可以看到我正在尝试做的事情。 I got this far and I just decided to not finish the end of the query (select the top N from each category), sorry. 我到此为止,我只是决定不结束查询的结尾(从每个类别中选择前N个),对不起。 :P :P

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM