我在从mysql数据库两侧CSV中选择一些数据时遇到问题

时间:2018-11-25 13:29:43

标签: php mysql mysqli

我有像

这样的双方昏迷分开的值
 $ing=1,2,3,4,5,6

并且数据库有一个带有值的表

 IDS    5,2,1,6,2,3,45 // in database

我知道这不是一个好习惯,但是我必须这样做才能在一个查询中获取值。我也有一个单独的表,其中IDS是单独的,并且对应于单独的用户,例如

  user 1    IDS 2 
  user 3    IDS 65 etc 

到目前为止,我正在使用

 $conditions[] = "CONCAT(',', `rcring`, ',') REGEXP ',($ing),'";

它给了我很好的结果,但是给了我其中一个$ ing存在的值,我只想要具有至少所有$ ing的表

请帮助我,我尝试了一下我的工作,但在任何地方都找不到合适的解决方案。谢谢。

      //EDIT

我已经有条件作为数组

   if($ser !=''){
                   $conditions[] = "rc_ser='$ser'";
                }if($fridge == 1){
                    $ing="0|";
                    $ctch2fr='checked';
                    foreach($_SESSION['fridge'] as $item){
                    $ing=$ing.$item."|";}
                   $conditions[] = "CONCAT(',', `rcring`, ',') REGEXP ',($ing),'";
                }
                 if (count($conditions) > 0) {
                $sql= implode(' AND ', $conditions);
                }

像这样作为数组中的条件,我在查询中这样称呼它

select * ,(select count(rcid) from recipe where ($sql)) as total from recipe where ($sql)

我尝试了以下答案,但总给我0个结果 当我打印查询时,它显示我是这样

 select *,(select count(rcid) from recipe where (CONCAT(',', `rcring`, ',') REGEXP ',(0),') ) as total from recipe where (CONCAT(',', `rcring`, ',') REGEXP ',(0),')

3 个答案:

答案 0 :(得分:3)

您似乎有一个配方表,其中包含用逗号分隔的成分列表:

5,2,1,6,2,3,45

以及给定成分的列表:

1,2,3,4,5,6

您想找到可以使用给定成分准备的食谱(食谱成分是给定成分的子集)。您需要编写构建以下查询的PHP代码:

SELECT *
FROM recipe
WHERE (
    FIND_IN_SET('1', rcring) > 0 AND
    FIND_IN_SET('2', rcring) > 0 AND
    FIND_IN_SET('3', rcring) > 0 AND
    FIND_IN_SET('4', rcring) > 0 AND
    FIND_IN_SET('5', rcring) > 0 AND
    FIND_IN_SET('6', rcring) > 0
)

基于您的尝试的PHP代码的粗略概述(您必须将其转换为准备好的语句):

$conditions = [];
foreach($fridge_ingredients as $ingredient) {
    $conditions[] = sprintf("FIND_IN_SET('%d', rcring) > 0", $ingredient);
}
$query = sprintf("SELECT *
FROM recipe
WHERE (%s)", implode(" AND ", $conditions));

话虽如此,正确的解决方案是规范化您的数据。这是结构的概述:

CREATE TABLE recipe (recipeid INT NOT NULL PRIMARY KEY, name VARCHAR(100));
CREATE TABLE ingredient (ingredientid INT NOT NULL PRIMARY KEY, name VARCHAR(100));
CREATE TABLE recipe_ingredient(recipeid INT NOT NULL,ingredientid INT NOT NULL, PRIMARY KEY(recipeid, ingredientid));

INSERT INTO recipe VALUES
(1, 'recipe 1'),
(2, 'recipe 2'),
(3, 'recipe 3'),
(4, 'recipe 4');
INSERT INTO ingredient VALUES
(1, 'ingredient 1'),
(2, 'ingredient 2'),
(3, 'ingredient 3'),
(4, 'ingredient 4');
INSERT INTO recipe_ingredient VALUES
(1, 1),
(2, 1), (2, 2),
(3, 1), (3, 2), (3, 3),
(4, 1), (4, 2), (4, 3), (4, 4);

查询:

SELECT *
FROM recipe
WHERE recipeid IN (
    SELECT recipeid
    FROM recipe_ingredient
    GROUP BY recipeid
    HAVING COUNT(CASE WHEN ingredientid IN (1, 2, 3) THEN 1 END) = COUNT(*)
)

结果:

recipeid  |  name
----------+----------
1         |  recipe 1
2         |  recipe 2
3         |  recipe 3

答案 1 :(得分:2)

据我所知,您指定的条件仅在rcring包含与子字符串完全相同的$ ing时才匹配,例如rcring = "5,2,1,6,2,3,45"与您的示例中的$ing = "1,2,3,4,5,6"不匹配。为了在此处匹配,rcring应该存储为"1,2,3,4,5,45"

这里的简单排序无济于事,因为$ing = "1,2,5,6"rcring = "1,2,3,4,5,6,45"不匹配

简单方法

使$conditions[]包含不同ID的匹配项,例如

<?
foreach (explode(",", $ing) as $key => $val) {
    $conditions[] = "CONCAT(',', `rcring`, ',') REGEXP ',($id),'"
}
?>

这将检查您想要的内容-如果rcing包含$ing的所有ID

但是,这对于大型(> 10 ^ 8行)表来说非常慢。这样的查询将在 O(n)时间内工作,检查表中的所有行。对于几GB的表,可能要花费一分钟以上的时间。

优化

使用Fulltext index searches。您需要存储以空格分隔的ID,例如1 2 3 4 5 45,以允许索引将其视为单词。 索引后,可以按如下方式重写代码:

<?
    $plus_ing = "+1 +2 +3 +4 +5"
    $conditions[] = "MATCh(`rcring`) AGAINST($plus_ing)"
?>

现在这将非常快地工作,并且会跳过完全不匹配的行!

请小心!

始终使用PHP::PDO并将ID作为参数传递!

黑客可能会通过传递一些危险而不是ID的方式进行SQL注入来滥用您的系统,例如:123");DROP DATABASE TEST; COMMIT;// 这会将$ings变成

"+1 +2 +123\");DROP DATABASE TEST; COMMIT;//"

最终查询将类似于

SELECT * FROM USERS WHERE MATCh(`rcring`) AGAINST(+1 +2 +123\");DROP DATABASE TEST; COMMIT;//");

正确的方法是PDO prepared statements howto,并始终以这种方式构造查询!

答案 2 :(得分:1)

您需要拆分$ing并在子句中检查其所有部分:

<?php
$ings = explode(',',$ing);
$conditions = array();
foreach($ings as $i) {
    $conditions[] = "CONCAT(',', `rcring`, ',') REGEXP ',(".intval($i)."),'";
}
$where = implode(' AND ', $conditions);
/* Use $where in where clause in your sql query */