У меня есть проблема с выбором некоторых данных из базы данных MySQL обе стороны CSV - PullRequest
0 голосов
/ 25 ноября 2018

У меня есть обе стороны, разделенные запятой, такие как

 $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

Можете ли вы помочь мне, пожалуйста, я попробовал свою работу и не могу найти правильное решение где-либо.Thankx.

      //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 голосов
/ 28 ноября 2018

Насколько я вижу, указанное вами условие соответствует только тогда, когда rcring содержит $ в точности как подстрока, например, 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[] содержать соединение совпадений по различнымИдентификаторы, например

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

Это проверит, что вы хотите - если rcing содержит все идентификаторы из $ing

Однако, это довольно медленно для больших (> 10 ^ 8строки) таблицы.Такие запросы будут работать в течение O (n) времени, проверяя все строки в таблице.Для нескольких гигабайтных таблиц это может занять значительно больше минуты.

Оптимизация

Использование Поиск по полнотекстовому индексу .Вам нужно хранить идентификаторы, разделенные пробелом, например, 1 2 3 4 5 45, чтобы индекс обрабатывал их как слова.После индексации код можно переписать следующим образом:

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

Теперь это будет работать довольно быстро и пропустит строки, которые вообще не совпадают!

БУДЬТЕ ОСТОРОЖНЫ!

Всегда используйте PHP :: PDO и передавайте идентификаторы в качестве параметров!

Хакеры могут злоупотреблять вашей системой, делая 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подготовил операторы howto и всегда так конструировал запросы!

0 голосов
/ 29 ноября 2018

Похоже, у вас есть таблица рецептов, которая содержит разделенный запятыми список ингредиентов:

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
0 голосов
/ 28 ноября 2018

Вам нужно разделить $ing и проверить все его части в предложении where:

<?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 */
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...