选择所有提交的复选框值都存在于 mySQL 列 [duplicate] 中以逗号分隔字符串形式的所有行

Select all rows where all submitted checkbox values exist in comma separated strings in mySQL column [duplicate]

提问人:Cyclopic 提问时间:11/18/2020 最后编辑:NickCyclopic 更新时间:11/18/2020 访问量:96

问:

我希望能够只将所有提交的行都存在于 中。我的代码选择具有任何已提交复选框值的行。SELECTWHEREcheckbox valueskeyWords

我有一个带有表格照片的mySQL数据库PhotoArchive

| id  | title   |filePath      | keyWords              |
| 1   | mypic1  |imgs/pic1.jpg | Mono,Portrait (etc)   |
| 2   | mypic1  |imgs/pic2.jpg | Colour,Portrait (etc) |
| 3   | mypic2  |imgs/pic2.jpg | Mono,Landscape (etc)  |
| 4   | mypic2  |imgs/pic2.jpg | Colour,Landscape (etc)|

我有一个带有复选框表单的 html 页面

<form action="selectFromDb.php" method="get">
<input type="checkbox" value="Mono" name="category[]" id="OptMono" />
  <label for="OptMono"> Monochrome</label>
<input type="checkbox" value="Colour" name="category[]" id="OptColour" />
  <label for="OptColour"> Colour</label>
<input type="checkbox" value="Portraits" name="category[]" id="OptPortraits" />
  <label for="OptPortraits"> Portraits</label>
<input type="checkbox" value="Landscape" name="category[]" id="OptLandscape" />
  <label for="OptLandscape"> Landscape</label>     
<input type="submit" value="Submit" />
以及使用此 SELECT 语句selectFromDb.php文件
 <? foreach($_GET['category'] as $category){
     $categories[] = $category;
   }
  $total_imgs_sql = "SELECT id, title, filePath FROM photos WHERE keyWords LIKE '%$category%'
 ?>

这将返回 中任何值所在的行。我只想返回所有$category关键字都存在的行。$categorykeyWordsWHERE

如何实现这一目标? (完整版有近 200 个复选框,每行可以有大约 20 个逗号分隔的单词)
谢谢
keyWords

php mysql 数组 select mysqli

评论

0赞 Cyclopic 11/18/2020
忘记了 SELECT 语句末尾的分号
0赞 Cyclopic 11/18/2020
@Dharman:重要的一点,但我正在根据白名单和mysqli检查每个$category,谢谢。

答:

1赞 Nick 11/18/2020 #1

为此,您可以在查询中构建一个类别值表,然后将其发送到该表中,并且仅选择返回与类别值表中行数相同的照片。作为示例查询,要查找包含和类别的照片,请执行以下操作:JOINphotosColourPortrait

SELECT p.*
FROM (
  SELECT 'Colour' AS keyWord
  UNION ALL
  SELECT 'Portrait' AS keyWord
) k
JOIN photos p ON CONCAT(',', p.keyWords, ',') LIKE CONCAT('%,', k.keyWord, ',%')
GROUP BY p.id
HAVING COUNT(*) = 2

db-fiddle 上的查询演示

在 PHP 中,您可以像这样生成此查询:

$categories = array('Colour', 'Portrait');

$sql = "SELECT p.*\nFROM (\n  SELECT '";
$sql .= implode("' AS keyword\n  UNION ALL\n  SELECT '", $categories);
$sql .= "' AS keyWord\n) k\nJOIN photos p ON CONCAT(',', p.keyWords, ',') LIKE CONCAT('%,', k.keyWord, ',%')\n";
$sql .= "GROUP BY p.id\nHAVING COUNT(*) = " . count($categories);

3v4l.org 上的PHP演示

请注意,为了便于阅读,我保留了使输出查询与上述查询匹配;您可以将它们替换为 (空格)。\n

另请注意,您可能对 SQL 注入持开放态度,您应该检查值以确保它们有效(使用关键字白名单),或转换为准备好的语句以避免这种情况。以下是使用预准备语句的方法(假设您使用的是 mysqli 并且您的连接在):$category$conn

$categories = array('Colour', 'Portrait');

$sql = "SELECT p.*\nFROM (\n  SELECT ";
$sql .= implode(" AS keyword\n  UNION ALL\n  SELECT ", array_fill(0, count($categories), '?'));
$sql .= " AS keyWord\n) k\nJOIN photos p ON CONCAT(',', p.keyWords, ',') LIKE CONCAT('%,', k.keyWord, ',%')\n";
$sql .= "GROUP BY p.id\nHAVING COUNT(*) = " . count($categories);

$stmt = $conn->prepare($sql);
$stmt->bind_param(str_repeat('s', count($categories)), ...$categories);
$stmt->execute();
$result = $stmt->get_result();
foreach ($result as $row) {
    print_r($row);
}

另请注意,如果您在后者中拥有每张照片/关键字组合一行的表格,而不是使用逗号分隔的数据,这将更简单(我强烈建议您阅读此问答)。keywordsphoto_keywords

评论

0赞 Nick 11/18/2020
@Dharman时间不多了,不得不去开会。我已经更新了答案。
0赞 Nick 11/18/2020
@Dharman实际上这个问题最初是被标记的,我把它改成了mysqlimysql
0赞 Cyclopic 11/18/2020
@Nick 非常感谢您非常慷慨的帮助 - 对我来说已经足够了。由于我缺乏经验,我需要一点时间来理解你的答案。如果我被卡住了(我想我可能会!我会在这里再次发表评论。
0赞 Nick 11/18/2020
@Cyclopic不用担心 - 我希望这是有用的。如果您有任何后续疑问,请再次评论,我会尽快回答。