管理MySQL层次结构数据

时间:2016-05-10 19:38:59

标签: mysql

我有一个“User_Info”。它包含所有用户信息以及每个用户所属公司的ID。

User_Id | User_Name | Company_Id
--------+-----------+--------------
1002    | User1     | 113
1003    | User2     | 114
1004    | User3     | 111

我有另一张表“公司”,其中包含公司信息及其相关的母公司。

id  | Company_Name    | Parent_Company_Id
----+-----------------+------------------
110 | WALMART         | NULL
111 | WALMART TEXAS   | 110
112 | WALMART DALLAS  | 111
113 | WALMART HOUSTON | 111
114 | WALMART KATY    | 113

如何获得以下输出? User_Info表中的Company_id应列出该Company_id下的所有分层公司。

user_id  | company_id
---------+--------------
1002     | 113
1002     | 111
1002     | 110
1003     | 114
1003     | 111
1003     | 110
1004     | 111
1004     | 110

1 个答案:

答案 0 :(得分:0)

您可以使用此查询(免责声明如下):

select user_id,
       company_id
from   (
        select     u.id as user_id,
                   c.id as company_id,
                   c.parent_company_id,
                   u.company_id as user_company_id
        from       user_info u,
                   company c
        order by   1, 2 desc
        limit      10000000000000000000
       ) base
where  company_id in (user_company_id, @p)
and    if(@p := parent_company_id, 1, 1)

声明

MySql不适合进行分层查询,因为它不支持ISO标准公用表表达式递归语法。

但MySql支持使用可在SQL语句执行期间修改的变量。这通常不是获得结果的可靠方法,因为MySql可以在执行查询时自由更改评估顺序和中间结果的顺序。

但是如果你愿意承担这个风险,上面的查询会将MySql引入某个序列,虽然这是有代价的:查询会在两个表之间执行笛卡尔积。

条件

有一个条件:公司记录应该都有父ID值,这些值不大于他们自己的ID。所以parent_company_id < id OR parent_company_id IS NULL必须对所有记录都是真的。否则上述查询将无法提供完整的结果。

查询说明

首先,内部查询返回笛卡尔积。订单很重要。这里假设MySql实际上将应用顺序,因为理论上,允许MySql忽略它并且可能使用有趣的索引。增加MySql应用order by的可能性的一种方法是设置限制。对于低限制,很明显MySql必须应用它的顺序来识别正确的记录。非常高限制的目标是强制MySql应用此订单,然后获取所有记录。

主要逻辑在where子句中。最初@p变量是null,因此当公司与用户的公司匹配时,第一个条件实际上将变为真。当发生这种情况时,第二个&#34;条件&#34;还将评估where子句的值。那个人确实是假的,因为它总是返回1,因此总是如此。但在评估时,变量@p更新为父公司ID,这是该条件&#34;的唯一目的。

现在,当测试另一条记录时,公司ID可以是用户公司,也可以是当前存储在@p中的母公司ID。这里显而易见的是,记录的顺序必须是用户ID,然后是公司ID,公司父母是在孩子之后订购的。这就是内部查询按降序排序公司ID的原因。

这是SQL fiddle