3

在我的系统中,每个项目都有一些标签。现在我想向用户展示带有标签的树。树应具有第一级的所有标签。
在每个一级标签内,应该再次出现在同样属于一级标签的项目中找到的所有标签。
在第三层,应该出现属于第一层和第二层的标签,以此类推。
这个想法是,用户可以根据他的标签过滤项目,并且可以改进在树中输入的过滤,而无需键入标签。

项目最初是作为字符串字段存储在项目表中的,但为了轻松实现此解决方案,我已将它们移动到子表中。

使用这些项目作为输入:

|Item       |Tags    |
|-----------|--------|
|Computer   |a,b,c   |
|Mouse      |a,c     |
|Keyboard   |c,d     |
|Monitor    |a,b     |

应该输出这棵树:

  Tree             Items that are show when selected

  root             Computer,Mouse,Keyboard,Monitor
    +--a           Computer,Mouse,Monitor
    |  +--b        Computer,Monitor
    |  |  +--c     Computer
    |  +--c        Computer,Mouse
    |     +--b     Computer
    +--b           Computer,Monitor
    |  +--a        Computer,Monitor
    |  |  +--c     Computer
    |  +--c        Computer
    |     +--a     Computer
    +--c           Computer,Mouse,Keyboard
    |  +--a        Computer,Mouse
    |  |  +--b     Computer
    |  +--b        Computer
    |  |  +--a     Computer
    |  +--d        Keyboard
    +--d           Keyboard
       +--c        Keyboard

此 SQL 应仅在 Oracle 数据库中运行,因此可以使用connect by运算符。

我从 Delicious 的 Firefox 扩展中选择了这种行为,它以树的形式显示标签,但限制它只有两个级别,我需要它显示尽可能多的级别。

你有什么主意吗?

提前致谢。

4

1 回答 1

0

[请原谅我的 SQL Server 语法......我的 Oracle 技能生疏了,我手头没有服务器]

在过去的十年中,我曾两次遇到过这个问题!

我的解决方案:

  1. 设计具有递归关系的单个表

    CREATE TABLE dummy(
      id        VARCHAR(128) NOT NULL,
      parent_id VARCHAR(128) NULL,
      --
      CONSTRAINT pk_dummy PRIMARY KEY(id),
      --
      CONSTRAINT fk_dummy_X_dummy
      FOREIGN KEY(id) REFERENCES dummy(id)
    )
    
  2. 为预先计算层次结构设计一个非规范化表:

    CREATE TABLE dummy_hierarchy(
      id        VARCHAR(128) NOT NULL,
      parent_id VARCHAR(128) NOT NULL,
      depth     INT NOT NULL
    )
    

    dummy_hierarchy具有以下属性:

    • id具有depth值为“1”的自我关系
    • id与其父级有关系,depth值为“2”
    • id与其祖父母有关系,depth值为“3”
    • 等等 ...

    还:

    • from idone 检索所有前辈,包括id它自己
    • from parent_idone 检索所有后继者,包括parent_id它自己
  3. 定义一个dummy应保持dummy_hierarchy最新的触发器:

    CREATE TRIGGER tr_dummy_ins_upd_del
    ON dbo.dummy FOR INSERT, UPDATE, DELETE
    AS
    BEGIN
      DELETE dummy
      FROM DELETED
      WHERE dummy.id = DELETED.id
    
      INSERT INTO dbo.dummy_hierarchy(
        id, parent_id, depth
      )
      SELECT id, id, 1
      FROM INSERTED
    
      WHILE 1 = 1
      BEGIN
        INSERT INTO dbo.dummy_hierarchy(
          id, parent_id, depth
        )
        SELECT hie.id, par.parent_id, hie.depth + 1
        FROM
          INSERTED ins
            INNER JOIN(
              dbo.dummy_hierarchy hie
                INNER JOIN dummy par
                ON par.id = hie.parent_id
            )
            ON hie.id = ins.id
        WHERE par.parent_id IS NOT NULL
          --
          AND NOT EXISTS(
                SELECT id
                FROM dummy_hierarchy hie_par
                WHERE hie_par.id        = hie.id
                  AND hie_par.parent_id = par.parent_id
              )
    
        IF @@ROWCOUNT = 0
        BEGIN
          BREAK
        END
      END
    END
    

    作为 POC 数据:

    INSERT INTO dummy(id, parent_id) VALUES('COMPUTER', NULL)
    INSERT INTO dummy(id, parent_id) VALUES('MONITOR',  'COMPUTER')
    INSERT INTO dummy(id, parent_id) VALUES('MOUSE',    'MONITOR')
    INSERT INTO dummy(id, parent_id) VALUES('KEYBOARD', 'MONITOR')
    

    查询:

    SELECT *
    FROM dbo.dummy_hierarchy hie
    WHERE parent_id = 'COMPUTER'
    

    产量:

        id         parent_id 深度
        电脑 电脑 1
        监控电脑 2
        鼠标电脑3
        键盘电脑 3
    

    这个:

    SELECT *
    FROM dbo.dummy_hierarchy hie
    WHERE parent_id = 'MONITOR'
    

    产量:

        id         parent_id 深度
        监视器监视器 1
        鼠标监视器 2
        键盘显示器 2
    

    并且,对于回溯:

    SELECT *
    FROM dbo.dummy_hierarchy
    WHERE id = 'MOUSE'
    

    有:

        id         parent_id 深度
        鼠标鼠标 1
        鼠标监视器 2
        鼠标电脑3
    

    当然,这并不完全是您所需要的。

    但我希望提供一些有用的线索。

于 2012-10-25T06:14:35.977 回答