【问题标题】:How to make a SQL to create a tag hierarchy based on items with the same tags?如何创建 SQL 以基于具有相同标签的项目创建标签层次结构?
【发布时间】:2012-10-23 11:09:33
【问题描述】:

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

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

使用这些项目作为输入:

|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 个实体上使用 4 个标签,您的树视图中有 19 行。使用大量标签和/或实体,这将爆炸成无法管理的数字。
  • 对。但是我不会有大量的标签,最多50个,只有当标签被选中时我才会加载它们,所以我认为这不是问题。但感谢评论。

标签: sql oracle tree tags hierarchy


【解决方案1】:

[请原谅我的 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 具有以下属性:

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

    还有:

    • id 检索所有前辈,包括id 本身
    • parent_id 检索所有后继者,包括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

    当然,这并不是你所需要的。

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

【讨论】:

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