Php 排序和筛选依赖项

Php 排序和筛选依赖项,php,algorithm,dependency-injection,php-5.3,topological-sort,Php,Algorithm,Dependency Injection,Php 5.3,Topological Sort,我正在优化报表系统的SQL查询,用户可以选择列,但表是固定的: -- Dynamically generated SELECT t1.c4, t4.c8 -- Static FROM t1 INNER JOIN t2 ON t1.id=t2.t1_id INNER JOIN t3 ON t1.id=t3.t1_id INNER JOIN t4 ON t2.id=t4.t2_id INNER JOIN t5 ON t4.id=t5.t4_id /*...*/; 我想删除不必要的表并动态生成整个查

我正在优化报表系统的SQL查询,用户可以选择列,但表是固定的:

-- Dynamically generated
SELECT t1.c4, t4.c8
-- Static
FROM t1
INNER JOIN t2 ON t1.id=t2.t1_id
INNER JOIN t3 ON t1.id=t3.t1_id
INNER JOIN t4 ON t2.id=t4.t2_id
INNER JOIN t5 ON t4.id=t5.t4_id
/*...*/;
我想删除不必要的表并动态生成整个查询:

-- Dynamically generated
SELECT t1.c4, t4.c8
FROM t1
INNER JOIN t2 ON t1.id=t2.t1_id
INNER JOIN t4 ON t2.id=t4.t12_id;
为了找出依赖关系,我在PackageGist中搜索并找到了和,它的工作原理与广告相同:

$sorter = new StringSort();
$sorter->add('t1');
$sorter->add('t2', array('t1'));
$sorter->add('t3', array('t1'));
$sorter->add('t4', array('t2'));
$sorter->add('t5', array('t4'));
print_r($sorter->sort());
数组
(
[0]=>t1
[1] =>t2
[2] =>t3
[3] =>t4
[4] =>t5
)
但我真正需要的是一种方法,它获取实际需要的一级表,并计算出符合依赖关系的最小表集,如:

// Sample interface and expected output
$query->getRequiredTables(array('t1', 't4'));
数组
(
[0]=>t1
[1] =>t2
[2] =>t4
)
我不能只使用一级表来馈送
->add()
,因为我将获得
ElementNotFoundException

这就是我迷路的地方。甚至拓扑排序都是正确的工具吗?

构建依赖关系树 首先,为表构建依赖关系树。例如,在您的情况下,它将是:

          1
         / \
        2   3
        |
        4
        |
        5
选择其中一个节点作为根节点 从所需表列表中选择任何表作为根。 例如,如果需要表2和表3,可以选择2作为根,并获得以下树:

          2
         / \
        4   1
        |   |
        5   3
遍历树并保存结果 现在从根遍历树,当您点击任何所需的表(在本例中为3)时,将堆栈中的所有表添加到结果中。例如,在节点3中,堆栈为[2,1,3],将所有这些节点添加到结果中

另一个例子 比方说,使用相同的依赖关系树,用户请求了表1、3和4。在本例中,将1作为根,当到达节点4时,堆栈为[1,2,4],当到达节点3时,堆栈为[1,3]。结果是[1,2,3,4]

示例代码 遍历树的示例代码(不使用任何特定语言,仅作为示例)


如果在表之间构建依赖关系图,则需要在两个表之间找到路径,以了解需要哪些表。例如,如果表依赖关系为(1,2)、(1,3)、(2,4)和(4,5),并且需要从表1和表4中获取值,则它们之间的路径为1->2->4,因此,您需要查询表1、2和4。@我知道这是一个路径,但我不知道如何正确计算它,特别是考虑到用户选择的列中涉及的表的数量可以从一个到所有。另外,我从大学开始就没用过图论,那是(叹气)在20世纪末。你们的依赖关系图有循环吗?还是一棵树?还有,你有多少张桌子?我已经放弃了marcj/topsort,我正在重新发明我自己的轮子,所以这真的很有帮助。“遍历”的确切含义是什么?它是深度优先搜索,以便我可以从堆栈中添加和删除?是的,使用深度优先搜索遍历树。如果结果中必须包含从根到该节点的路径,则可以使递归函数返回true。类似于:函数dfs(node){bool include=requiredTables.contain(node);对于节点的每个子节点:if dfs(child){include=true;}if(include)result.add(node);return include;}@elvarogonzález我已经更新了答案,以包含示例代码(来自前面的注释)。
function dfs(node) {
   bool include = requiredTables.contains(node)
   for each child of node {
     if dfs(child) {
       include = true;
     }
   }
   if (include) result.add(node);
   return include;
}