【问题标题】:MySQL how can I search for media in virtual foldersMySQL如何在虚拟文件夹中搜索媒体
【发布时间】:2015-08-03 09:36:24
【问题描述】:

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

虚拟文件夹的结构是:

表目录

id name parent

媒体的结构是:

表格媒体

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

现在假设我有以下文件夹

    • 项目1
      • 目录 1
        • 子目录 1
        • 子目录 2
        • 子目录 3
      • 目录 2
        • 子目录 1
      • 目录 3
        • 子目录 1
        • 子目录 2
    • 项目2
      • 目录 1
        • 子目录 1
        • 子目录 2
      • 目录 2
        • 子目录 1
        • 子目录 2
        • 子目录 3
      • 目录 3
        • 子目录 1
    • 项目3
      • 目录 1
        • 子目录 1
      • 目录 2
        • 子目录 1
      • 目录 3
        • 子目录 1

我想在“项目 1”中搜索名为“%media_1%”的媒体,包括其所有子文件夹,如何在不查询每个文件夹和子文件夹的情况下做到这一点?子文件夹的级别可能会有所不同。

【问题讨论】:

  • 除非您知道最大深度,否则我不确定没有不同的表结构是否可行。
  • 那是我的恐惧,你知道表结构会做什么吗?考虑到我需要一些动态的东西(移动文件夹,重命名它们等等......)
  • 如何以最大深度做到这一点?每个级别的连接?
  • 是的,每个级别的连接,包括前面的级别,我会在几分钟内以答案形式举例说明

标签: php mysql search directory subdirectory


【解决方案1】:

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

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”子句,中间节点将不会被包括在内。 如果不需要中间节点并且“叶”节点的深度不同,则INNER JOINs 需要为LEFT JOINs,而SELECT 字段会稍微复杂一些:

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

交替

您可以有一个额外的表格来汇总总祖先,最简单的版本将有两个字段ancestor_iddescendant_id(尽管您也可以包括“距离”)。最大的问题是它需要通过某种形式的代码来维护,树表上的触发器可能是最有效和最可靠的方法。

【讨论】:

  • 你能用 Example 解释更多关于祖先 ID 和后代 ID 的信息吗?
  • 基本思想是当一个节点被插入到树表中时,插入可能是在“祖先”表中。一个用于父节点(距离为 1),以及父节点的祖先副本(距离 + 1)(又名。INSERT INTO ancestors(a_id, d_id, distance) SELECT a_id, [new_node_id], distance + 1 FROM ancestors WHERE d_id = [id_of_new_node's_parent])。显然,删除时也需要更新内容。
  • 我需要展示n级树,并想制作虚拟目录树。 CREATE TABLE 目录 (id int, name varchar(50), parent_id varchar(10)) ;插入目录 (id, name, parent_id) 值 (1, 'root', ''), (2, 'SuperCat1', 1), (3, 'SuperCat2', 1), (4 , 'Cat11', 2), (5, 'Cat12', 2), (6, 'Cat21', 3), (7, 'Cat22', 3), (8, 'Cat23', 3), (9 , 'SubCat231', 8), (10, 'SubCat232', 8) ;
  • 选择 b.name 作为 layer2,c.name 作为 layer3,d.name 作为 layer4 FROM 目录 a,目录 b,目录 c,目录 d WHERE(a.id = b.parent_id OR a. id = b.id) and (b.id = c.parent_id or b.id = c.id) and (c.id = d.parent_id or c.id = d.id) and a.id = 1跨度>
【解决方案2】:

好的,所以我找到了一个解决方案,我正在使用上面发布的函数来获取给定目录的所有子目录的 ID,假设“项目 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%'

请求将只搜索“项目1”及其子目录中的媒体,无论多少级

【讨论】:

  • 除非我遗漏了什么,否则它看起来只会获得直接的子目录。
  • 你错过了电话 print_menu($data['id']);每次完成一个目录时,它都会调用它的子目录,直到一个目录都没有。
  • 啊,我完全忽略了递归;我虽然发布问题的人希望避免多次查询。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-12-03
  • 2010-10-03
  • 1970-01-01
相关资源
最近更新 更多