【问题标题】:writing SQL query with nested sets使用嵌套集编写 SQL 查询
【发布时间】:2012-02-27 07:51:02
【问题描述】:

我需要编写一个查询来执行搜索,其中所有结果都按类别匹配。
这些类别有子类别,它们作为嵌套集模型工作,每个类别都有一个 lft 和一个 rgt 列。

如果cat2cat3cat4cat1 的子级,那么它们的.lft介于 cat1.lftcat1.rgt

所有类别都存储在CATEGORIES 表中,并以ID 作为主键。

我需要的是一个类别ID 查找ITEMS 表上属于该类别的所有项目,以及属于类别子类别的所有项目。

我正在寻找的查询是这样的

 SELECT i.id, i.name
 FROM items AS i, categories AS c
 WHERE i.category_lft BETWEEN c.given_cat_id_lft AND c.given_cat_id_rgt

我的意思是我得到类别主键 (ID) 但在查询中我需要使用它们的 rgt 和 ltf 值

我应该使用子查询还是联接? 查询应该如何? 我真的没有 SQL 方面的经验。

【问题讨论】:

  • 看到这个question
  • items 表是否存储项目的 category_id(如 ypercube 的回答中所假设的那样)或其 category_lft 值(如问题中提供的示例查询中所暗示的那样)?

标签: sql join mysqli subquery nested-sets


【解决方案1】:
 SELECT i.id
      , i.name
 FROM items AS i
   JOIN categories AS c
     ON i.category_id = c.id
   JOIN categories AS myc
     ON c.category_lft BETWEEN myc.lft AND myc.rgt
 WHERE myc.id = @GivenCategoryID

【讨论】:

    【解决方案2】:

    试试这个:

    CREATE table #Category(
    id      INT NOT NULL,
    name    VARCHAR(20) NOT NULL,
    parentid    INT NOT NULL
    )
    
    INSERT INTO #Category (id, name, parentid) VALUES
    (1, 'parts', 1),
    (2, 'processor', 1),
    (3, 'AMD', 2),
    (4, 'Intel', 2),
    (5, 'Hard Disk', 1),
    (6, 'Memory', 1),
    (7, 'DDR1', 6),
    (8, 'DDR2', 6),
    (9, 'DDR3', 6),
    (10, '533Mhz', 7),
    (11, '667Mhz', 8),
    (12, '800Mhz', 8)
    
    CREATE table #Items(
    id      INT NOT NULL,
    name    VARCHAR(20) NOT NULL,
    categoryId  INT NOT NULL
    )
    
    INSERT INTO #Items (id, name, categoryId) VALUES
    (1, 'AMD Phenom', 3),
    (2, 'AMD Sempron', 3),
    (3, 'AMD Athlon', 3),
    (4, 'Intel core 2 duo', 4),
    (5, 'Intel core i3', 4),
    (6, 'DDR2 1GB 6667Mhz', 11),
    (7, 'Intel 8080', 4),
    (8, 'Intel 80286', 4),
    (9, 'Intel 80386', 4),
    (10, 'Intel 80486', 4),
    (11, 'Intel Pentuim', 4),
    (12, 'Intel Pentium I', 4)
    
    
    DECLARE @TopLevelId INT; -- top level category Id
    SET @TopLevelId = 2;   -- top level category = AMD processors
    
    WITH CTE AS
    (SELECT id, name, parentid, id as Adam, 1 as level
    FROM #Category
    WHERE id = @TopLevelId
    UNION ALL
    SELECT #Category.id, #Category.name, #Category.parentid, CTE.Adam, CTE.level + 1
    FROM #Category 
    INNER JOIN CTE ON
        #Category.parentid = CTE.id
    WHERE #Category.id <> @TopLevelId
    )
    SELECT CTE.id CategoryId, CTE.name as Category, #Items.name as Item
    FROM CTE
    INNER JOIN #Items ON
        CTE.id = #Items.categoryId
    ORDER BY level, CTE.id
    
    
    DROP table #Category
    DROP table #Items
    

    【讨论】:

    • 这个问题与 MySQL 相关,而不是 SQLServer。
    【解决方案3】:

    你需要递归 SQL 来解决这个问题。

    首先找到具有给定类别的所有子类别,如父、祖父母、祖父母、...(不要忘记包括给定类别本身)。

    然后将这些子类别与您的 Items 表中的类别连接起来。

    我会忘记 lft 和 rght 值。完成这项工作将是一项艰巨的工作。 (BETWEEN 将如何工作?基于 Id 的值?您能想象在现有子类别之间的某处插入子类别的后果吗?)

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多