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

时间:2014-12-30 15:06:25

标签: php sql fetch

我正在尝试使用标签构建搜索功能

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。有没有人有不同的方法去做?我尝试过使用几种不同的fetch类型,但是我一直在array_diff上获得数组到字符串的转换错误。

由于

2 个答案:

答案 0 :(得分:1)

查询中没有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 ()条件中的标记名称列表将在$keywords的PHP代码中生成。

运行查询后的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 ---+

答案 1 :(得分:0)

如果我理解正确,您可以解决如下问题。多维数组diff

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