我有一个“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
答案 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。