有帮助吗?

解决方案

要跨越做一个简单的邻接表多层次的查询总是涉及自左联接。这很容易使一个右对齐的表:

SELECT category.category_id,
    ancestor4.category_id AS lvl4,
    ancestor3.category_id AS lvl3,
    ancestor2.category_id AS lvl2,
    ancestor1.category_id AS lvl1
FROM categories AS category
    LEFT JOIN categories AS ancestor1 ON ancestor1.category_id=category.category_id
    LEFT JOIN categories AS ancestor2 ON ancestor2.category_id=ancestor1.parent
    LEFT JOIN categories AS ancestor3 ON ancestor3.category_id=ancestor2.parent
    LEFT JOIN categories AS ancestor4 ON ancestor4.category_id=ancestor3.parent;

要左对齐它喜欢你的例子是比较麻烦一些。此想到:

SELECT category.category_id,
    ancestor1.category_id AS lvl1,
    ancestor2.category_id AS lvl2,
    ancestor3.category_id AS lvl3,
    ancestor4.category_id AS lvl4
FROM categories AS category
    LEFT JOIN categories AS ancestor1 ON ancestor1.parent IS NULL
    LEFT JOIN categories AS ancestor2 ON ancestor1.category_id<>category.category_id AND ancestor2.parent=ancestor1.category_id
    LEFT JOIN categories AS ancestor3 ON ancestor2.category_id<>category.category_id AND ancestor3.parent=ancestor2.category_id
    LEFT JOIN categories AS ancestor4 ON ancestor3.category_id<>category.category_id AND ancestor4.parent=ancestor3.category_id
WHERE
    ancestor1.category_id=category.category_id OR
    ancestor2.category_id=category.category_id OR
    ancestor3.category_id=category.category_id OR
    ancestor4.category_id=category.category_id;
  

将工作的n层层次结构。

对不起,任意深度的查询是不可能在邻接列表模型。如果你正在做这种查询了很多,你应该将模式切换到的其他型号的:全邻接关系(存储所有祖先的后代关系),物化路径,或嵌套集合

如果类别不走动很多(通常是像您的例子的店铺的情况下),我会趋向嵌套集。

其他提示

如所提到的,SQL没有干净的方式来实现与列的动态变化数量的表。我以前使用的只有两种解决方法: 1.一种固定数量的自联接,给列的固定数量(AS每BobInce) 2.生成的结果作为字符串在单个列

最初的第二个声音奇形怪状;存储ID作为字符串?但是,当输出格式为XML或什么的,人们似乎并不介意这么多。

同样,这是很少使用的,如果你那么想加入对SQL的结果。如果结果是要提供给应用程序,它可以是非常合适的。就我个人而言,我喜欢做的应用程序,而不是SQL扁平化

,点击 我在这里停留一个10英寸的屏幕上没有访问SQL,所以我不能给被测试代码,但基本的方法是利用某种方式递归;点击 - 递归标量函数可以做到这一点点击 - MS SQL可使用WITH语句递归做到这一点(更有效)

<强>标量函数(像):

CREATE FUNCTION getGraphWalk(@child_id INT)
RETURNS VARCHAR(4000)
AS
BEGIN

  DECLARE @graph VARCHAR(4000)

  -- This step assumes each child only has one parent
  SELECT
    @graph = dbo.getGraphWalk(parent_id)
  FROM
    mapping_table
  WHERE
    category_id = @child_id
    AND parent_id IS NOT NULL

  IF (@graph  IS NULL)
    SET @graph = CAST(@child_id AS VARCHAR(16))
  ELSE
    SET @graph = @graph + ',' + CAST(@child_id AS VARCHAR(16))

  RETURN @graph

END


SELECT
  category_id                         AS [category_id],
  dbo.getGraphWalk(category_id)       AS [graph_path]
FROM
  mapping_table
ORDER BY
  category_id

我有一段时间没有使用的是递归的,但我给的语法去,即使我没有SQL在这里做测试任何东西:)

<强>递归WITH

WITH
  result (
    category_id,
    graph_path
  )
AS
(
  SELECT
    category_id,
    CAST(category_id AS VARCHAR(4000))
  FROM
    mapping_table
  WHERE
    parent_id IS NULL

  UNION ALL

  SELECT
    mapping_table.category_id,
    CAST(result.graph_path + ',' + CAST(mapping_table.category_id AS VARCHAR(16)) AS VARCHAR(4000))
  FROM
    result
  INNER JOIN
    mapping_table
      ON result.category_id = mapping_table.parent_id
)

SELECT
  *
FROM
  result
ORDER BY
  category_id

,点击 修改 - 输出两者是相同的:

1   '1'
2   '1,2'
3   '1,2,3'
4   '1,2,4'
5   '1,2,5'
6   '1,6'
7   '1,6,7'
8   '1,6,7,8'
9   '1,6,9'

遍历任意深度的树通常涉及递归程序代码,除非你使用一些DBMS的特殊功能。

在Oracle中,CONNECT BY子句将允许您遍历树深度优先顺序,如果你使用邻接表,因为你没有在这里。

如果您使用嵌套组,左序列号会为您提供的顺序访问节点。

实际上可以与存储程序内动态SQL来完成。然后,您成为限于可以西斯的存储过程来完成。显然,这成为给EXEC结果到一个临时表,不知道有多少列期待一个挑战。但是,如果我们的目标是要输出到网页或其他UI那么它可能是值得的......

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top