Соединение двух таблиц с условием 'whereNotIn' возвращает неправильные строки в Laravel - PullRequest
0 голосов
/ 15 октября 2018

У меня есть две таблицы:

TABLE_A имеет следующие столбцы:

id - rule_id - car_id

100 - 3 - 5

101 - 4 - 5

102 - 2 - 6

103 - 3 - 6

и TABLE_B имеет больше столбцов, но те, которые необходимы здесь:

id - car_id

70 - 5

71 - 6

Я хочу объединить эти две таблицы.Мой код ниже:

$ruleIds = [1,2,3]; // Got from user: User wants to see cars that are not included in those(1,2,3) rules.
$cars = Car::where('type', $type);
$result = $cars->join('rule', 'rule.car_id', 'car.car_id')
    ->whereNotIn('rule.rule_id', $ruleIds);

, но MySQL делает следующее:

Объединяет две таблицы на rule.car_id и car.car_id Проверки, где rule.rule_id != 1, rule.rule_id != 2, rule.rule_id != 3.

Однако для car_id из 6 он возвращает запись, в то время как я объявил whereNotIn('rule.rule_id', [1,2,3]).Он говорит себе, что car_id из 6 не имеет rule_id из 2, но второй с rule_id из 3 не равен 2, поэтому он снова возвращает запись.

Как я могу предотвратить возврат записей для каждого условия вчтобы не возвращать значение, если одно из whereNotIn условий не обязательно соответствует всем им?

, например: если я (как пользователь) установил 1,2 для правил, он не должен возвращать автомобиль сcar_id = 6 из таблицы cars, потому что в таблице правил у нас есть правило, что его rule_id равен 2 (одно из правил, которое я (пользователь) установил).

Так что, если 1..Возвратить все, если 2..Вернутьcar_id из 5, если 3.. Чтобы вернуть нет, если 1,2,3,4 .. Чтобы вернуть нет

Относительно "Отредактируйте свой вопрос и покажите пример вывода на основе rules_id = (1, 2). Показатьэто как таблица, а не как неразборчивый текст ".Я хочу, чтобы возвращаемое значение было:

Array ()

enter image description here

Ответы [ 3 ]

0 голосов
/ 15 октября 2018
$posts = App\Car::whereHas('rules', function ($query)use($ruleIds) {
    $query->whereNotIn('rule_id',  $ruleIds);
})->get();
0 голосов
/ 16 октября 2018

Я мог бы решить проблему с помощью ответа @TimBiegeleisen:

$paramValues = explode(',', $data['rules']);
$paramKeys = '';
for($p=1; $p<=$paramCount; $p++)
{
    $paramKeys .= '?,';
}
$paramKeys = rtrim($paramKeys, ',');

$cars->join('rule', 'rule.car_id', 'cars.car_id')
    ->whereRaw("cars.car_id NOT IN (SELECT car_id FROM rule WHERE rule_id IN (".$paramKeys."))", $paramValues)
    ->groupBy('cars.car_id');
  1. Я прошу прощения за плохой английский или плохое объяснение:)
  2. Для предотвращения инъекции sqlЯ сделал это для цикла.Есть ли какой-нибудь другой лучший подход для этого?
  3. В запросе есть другой выбор, но я хотел сделать это только с помощью join и simple.Есть ли другой способ получить это?

Спасибо всем:)

0 голосов
/ 15 октября 2018

Вот как может выглядеть ваш необработанный запрос MySQL:

SELECT *
FROM TABLE_A a
INNER JOIN TABLE_B b
    ON a.car_id = b.car_id
WHERE
     NOT EXISTS (SELECT 1 FROM TABLE_A a2
                 WHERE a.car_id = a2.car_id AND a2.rule_id IN (1, 2));

Код Laravel:

$cars = Car::where('type', $type);
$result = $cars->join('rule', 'rule.car_id', 'car.car_id')
    ->where(DB::raw("NOT EXISTS (SELECT 1 FROM rule r2
                 WHERE rule.car_id = r2.car_id AND r2.rule_id IN (1, 2))"));

Обратите внимание, что я не пытался сделать значения rule_idВы хотите, чтобы экран динамический.То есть я не привязываю ваш массив $ruleIds к запросу.Причина этого заключается в том, что это трудно сделать по неизвестному количеству правил.Но приведенный выше код должен поставить вас на правильный путь.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...