排序和过滤依赖项

时间:2017-09-08 12:09:08

标签: php algorithm dependency-injection php-5.3 topological-sort

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

        <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-antrun-plugin</artifactId>
            <version>1.8</version>
            <executions>
                <execution>
                    <phase>install</phase>
                    <configuration>
                        <target>
                            <copy file="target/${project.artifactId}-exec.jar" tofile="../../docker/${project.artifactId}.jar"/>
                        </target>
                    </configuration>
                    <goals>
                        <goal>run</goal>
                    </goals>
                </execution>
            </executions>
        </plugin>

我想删除不必要的表并动态生成整个查询:

-- 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
/*...*/;

为了找出依赖关系,我在Packagist中进行了搜索,找到了marcj/topsorttopological sorting,其工作原理如下:

-- 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;
$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());

但我真正需要的是一种方法,该方法需要实际需要的第一级表,并计算出符合依赖性的最小表集,如:

Array
(
    [0] => t1
    [1] => t2
    [2] => t3
    [3] => t4
    [4] => t5
)
// Sample interface and expected output
$query->getRequiredTables(array('t1', 't4'));

我不能仅使用第一级表格提供Array ( [0] => t1 [1] => t2 [2] => t4 ) ,因为我会得到->add()

在这里,我迷失了方向。甚至拓扑排序是正确的工具吗?

1 个答案:

答案 0 :(得分:1)

构建依赖关系树

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

          1
         / \
        2   3
        |
        4
        |
        5

以root身份选择其中一个节点

以root身份从所需的表列表中选择任何表。 例如,如果需要表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]。

示例代码

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

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;
}