Select products where the category belongs to any category in the hierarchy

前端 未结 9 1654
再見小時候
再見小時候 2021-02-06 05:39

I have a products table that contains a FK for a category, the Categories table is created in a way that each category can have a parent category, example:

Compu         


        
相关标签:
9条回答
  • 2021-02-06 06:24

    Looks like a job for a Common Table Expression.. something along the lines of:

    with catCTE (catid, parentid)
    as
    (
    select cat.catid, cat.catparentid from cat where cat.name = 'Processors'
    UNION ALL
    select cat.catid, cat.catparentid from cat inner join catCTE on cat.catparentid=catcte.catid
    )
    select distinct * from catCTE
    

    That should select the category whose name is 'Processors' and any of it's descendents, should be able to use that in an IN clause to pull back the products.

    0 讨论(0)
  • 2021-02-06 06:25

    What you want to find is the transitive closure of the category "parent" relation. I suppose there's no limitation to the category hierarchy depth, so you can't formulate a single SQL query which finds all categories. What I would do (in pseudocode) is this:

    categoriesSet = empty set
    while new.size > 0:
      new = select * from categories where parent in categoriesSet
      categoriesSet = categoriesSet+new
    

    So just keep on querying for children until no more are found. This behaves well in terms of speed unless you have a degenerated hierarchy (say, 1000 categories, each a child of another), or a large number of total categories. In the second case, you could always work with temporary tables to keep data transfer between your app and the database small.

    0 讨论(0)
  • 2021-02-06 06:31
    CREATE TABLE #categories (id INT NOT NULL, parentId INT, [name] NVARCHAR(100))
    INSERT INTO #categories
        SELECT 1, NULL, 'Computers'
        UNION
    SELECT 2, 1, 'Processors'
        UNION
    SELECT 3, 2, 'Intel'
        UNION
    SELECT 4, 2, 'AMD'
        UNION
    SELECT 5, 3, 'Pentium'
        UNION
    SELECT 6, 3, 'Core 2 Duo'
        UNION
    SELECT 7, 4, 'Athlon'
    SELECT * 
        FROM #categories
    DECLARE @id INT
        SET @id = 2
                ; WITH r(id, parentid, [name]) AS (
        SELECT id, parentid, [name] 
            FROM #categories c 
            WHERE id = @id
            UNION ALL
        SELECT c.id, c.parentid, c.[name] 
            FROM #categories c  JOIN r ON c.parentid=r.id
        )
    SELECT * 
        FROM products 
        WHERE p.productd IN
    (SELECT id 
        FROM r)
    DROP TABLE #categories   
    

    The last part of the example isn't actually working if you're running it straight like this. Just remove the select from the products and substitute with a simple SELECT * FROM r

    0 讨论(0)
提交回复
热议问题