使用用户提供的数组进行 SQL 提取


SQL fetch with user supplied array

我正在尝试使用标签构建搜索函数,

我在 MySQL 中的数据结构

parts                           parts_to_tags            tags
---------------------- ----    -------------------      -----------------
| part_id | part_name     |    |id|part_id|tag_id|      |tag_id|tag_name|
|  1      | 20lb Sledge   |    | 1|      1|     1|      |     1|Hammer  |
|  2      | Framing Hammer|    | 2|      1|     2|      |     2|Sledge  |
|         |               |    | 3|      2|     1|      

我有一个由用户在数组中提供的标签列表,我想将其与这些表进行比较以返回所有结果,因此如果用户要求锤子,则应返回两个工具,但如果他们要求两者或只是雪橇,则应返回 20 磅的雪橇。我不想使用 SQL"IN",因为我想将其用作向下钻取,不是如果存在任何标签,而是结果必须存在所有标签。

我的代码:

    $keywords = $_POST['tags'];
     // Returns: Array ( [0] => Sledge [1] => Hammer )
    $getInventory = $conn -> prepare("SELECT * FROM 
            parts
            LEFT JOIN parts_to_tags ON parts.part_id = parts_to_tags.part_id
            LEFT JOIN tags ON parts_to_tags.tag_id   = tags.tag_id
            ");
    $getInventory -> execute();
    $partArray = $getInventory -> fetchAll();

             $matched = !array_diff($keywords, $partArray);
             print_r($matched);

但是,$partArray似乎是一个深度数组,所以我无法使用array_diff。有没有人有不同的方法可以解决这个问题?我尝试使用几种不同的提取类型,但我不断在array_diff上收到数组到字符串的转换错误。

谢谢

查询中没有 WHERE 子句;它将返回整个表,这不是你需要的。此外,即使您添加了 WHERE 子句,LEFT JOIN 仍将返回您需要的更多行。

问题的一个可能解决方案可能是:

SELECT p.part_id, p.part_name, GROUP_CONCAT(t.tag_name ORDER BY t.tag_name SEPARATOR '|') AS tags
FROM parts p
    INNER JOIN parts_to_tags pt ON p.part_id = pt.part_id
    INNER JOIN tags t ON pt.tag_id = t.tag_id
WHERE t.tag_name IN ('Hammer', 'Sledge')
GROUP BY p.part_id

它选择至少具有一个标签的部件,以及与每个部件关联的标签列表,按升序排序并按"|"分隔。

当然,IN ()条件下的标签名称列表会在 PHP 代码中从 $keywords 生成。

运行查询后PHP代码:

// Sort the keywords ascending
sort($keywords);
// Concatenate them, use '|' as separator
$allTags = implode('|', $keywords);
// Get the result set
$parts = array();
foreach ($getInventory -> fetchAll() as $row) {
    // Keep only the parts that have all the tags
    if ($row['tags'] == $allTags) {
        $parts[] = $row;
    }
}

UPDATE:查询的简化版本,仅返回具有所有指定标记的部分(不需要额外的 PHP 处理):

SELECT p.part_id, p.part_name, COUNT(t.tag_name) AS nbTags
FROM parts p
    INNER JOIN parts_to_tags pt ON p.part_id = pt.part_id
    INNER JOIN tags t ON pt.tag_id = t.tag_id
WHERE t.tag_name IN ('Hammer', 'Sledge')       # <----------------+
GROUP BY p.part_id        #                                       |
HAVING nbTags = 2         # The number of strings in this list ---+

如果我理解正确,您可以按如下方式解决。多维数组差异

function arrayRecursiveDiff($aArray1, $aArray2) {
  $aReturn = array();
  foreach ($aArray1 as $mKey => $mValue) {
    if (array_key_exists($mKey, $aArray2)) {
      if (is_array($mValue)) {
        $aRecursiveDiff = arrayRecursiveDiff($mValue, $aArray2[$mKey]);
        if (count($aRecursiveDiff)) { $aReturn[$mKey] = $aRecursiveDiff; }
      } else {
        if ($mValue != $aArray2[$mKey]) {
          $aReturn[$mKey] = $mValue;
        }
      }
    } else {
      $aReturn[$mKey] = $mValue;
    }
  }
  return $aReturn;
} 
  $arr1 =    arrayRecursiveDiff($big_array,$small_array);