MySQL 如何在虚拟文件夹中搜索媒体

MySQL how can I search for media in virtual folders

我正在想办法为我的媒体数据库制作一个搜索引擎。

虚拟文件夹的结构是:

table 目录

id name parent

媒体的结构是:

table 媒体

id name parent

我正在使用以下 php 函数来列出我的所有目录

function print_menu($id = 0) {
    $sql = "SELECT directories.id AS id, directories.name AS name, directories.parent AS parent, directories.icon AS icon FROM directories 
    WHERE directories.parent = '".$id."' GROUP BY directories.id ORDER BY directories.name ASC";
    $req = $cnx->prepare($sql);
    $req->execute();
    if ($req->rowCount()>0) {
        echo "<ul>";
        while ($data=$req->fetch()) {
            echo "<li>".$data['name']."</li>";
            print_menu($data['id']);
        }
        echo "</ul>";
    }
 }

现在假设我有以下文件夹

我想在 "project 1" 中搜索名为“%media_1%”的媒体,包括它的所有子文件夹,如何在不查询每个文件夹和子文件夹的情况下执行此操作?子文件夹的级别可以变化。

好的,所以我找到了一个解决方案,我正在使用上面发布的函数来获取给定目录的所有子目录的 ID,假设 "project 1" 的 ID 为 42 我将使用

$all_ids = array();
function print_menu($id = 0) {
    $sql = "SELECT directories.id AS id, directories.name AS name, directories.parent AS parent, directories.icon AS icon FROM directories 
    WHERE directories.parent = '".$id."' GROUP BY directories.id ORDER BY directories.name ASC";
    $req = $cnx->prepare($sql);
    $req->execute();
    if ($req->rowCount()>0) {
        while ($data=$req->fetch()) {
            $all_ids[] = $data['id'];
            print_menu($data['id']);
        }
    }
 }
all_ids[] = 42;
print_menu(42)

那么我只是在做一个像

这样的请求
SELECT * FROM medias WHERE medias.parent IN (".implode(',', $all_ids).") AND medias.name LIKE '%media_1%'

请求只会在"project 1"及其子目录中搜索媒体,无论有多少层

一般来说,使用 "tree" table,要获取所有后代的列表,以及已知的最大深度,您可以构造如下查询:

SELECT layerN.ID
FROM theTable AS layer1
   INNER JOIN theTable AS layer2 
      ON layer1.id = layer2.parent_id 
      OR layer1.id = layer2.id
   INNER JOIN theTable AS layer3
      ON layer2.id = layer3.parent_id 
      OR layer2.id = layer3.id
   ...
   INNER JOIN theTable AS layerN
      ON `layerN-1`.id = layerN.parent_id 
      OR `layerN-1`.id = layerN.id
WHERE layer1.parent_id = [chosen_parent_node_id]
;

如果 ON 条件中没有额外的 "OR" 子句,则不会包括中间节点。 如果不需要中间节点,"leaf"节点深度不一,则INNER JOINs需要LEFT JOINs,SELECT字段多一点复杂:

SELECT IFNULL(layerN.id, IFNULL(`layerN-1`.id, IFNULL(....))) AS leafID

交替

你可以有一个额外的 table 来总结总祖先,最简单的版本会有两个字段 ancestor_iddescendant_id(尽管你可以包括一个 "distance" 作为出色地)。最大的问题是它需要通过某种形式的代码来维护,树上的触发器table可能是最有效和可靠的方法。