【问题标题】:Joining two tables with the condition of 'whereNotIn' returns wrong rows in Laravel在 Laravel 中加入条件为“whereNotIn”的两个表会返回错误的行
【发布时间】:2019-03-19 11:43:51
【问题描述】:

我有两张桌子:

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_idcar.car_id 上加入两个表 检查rule.rule_id != 1rule.rule_id != 2rule.rule_id != 3 的位置。

但是对于 6 的 car_id,它会在我声明 whereNotIn('rule.rule_id', [1,2,3]) 时返回记录。它对自己说 6 的 car_id 没有 2 的 rule_id 但第二个 3 的 rule_id 不等于 2 所以它再次返回记录。

如果whereNotIn 条件之一不一定匹配所有条件,我如何防止返回每个条件的记录以便不返回值?

例如:如果我(作为用户)为规则设置 1,2,它不应该从汽车表中返回 car_id 为 6 的汽车,因为在规则表中我们有一个规则,它的 rule_id 为 2(其中一个规则我(用户)设置)。

所以如果 1..返回所有 如果 2..返回 5 的 car_id 如果 3..不返回 if 1,2,3,4..不返回

关于“编辑您的问题并根据 rules_id = (1, 2) 显示示例输出。将其显示为表格,而不是难以辨认的文本。”我希望返回值为:

数组()

【问题讨论】:

  • 您的预期输出是什么样的?
  • 返回值是汽车表car_id列与规则表car_id列匹配的所有记录。我只想返回不在用户设置的规则表 rule_id 列中的值。
  • 编辑您的问题并显示基于rules_id = (1, 2) 的示例输出。将其显示为 table,而 not 显示为难以辨认的文本。
  • 请阅读minimal reproducible example并采取行动。这包括一个明确的规范。现在你不清楚。例如,诸如“检查”和“它对自己说”之类的模糊非正式动词不清楚;很明显,它返回 rule.rule_id != 1 和 rule.rule_id != 2 和 rule.rule_id != 3 的行。你给出了一堆关于你不希望错误查询做什么的不清楚的句子等请使用足够的技术术语和短语和句子来清楚。请根据输入中的行明确说明您希望输出中的哪些行。
  • 嗨。请use text, not images/links, for text (including code, tables & ERDs)。使用链接/图像仅是为了方便补充文本和/或无法在文本中给出的内容。这将是一个常见问题解答。请始终在谷歌上搜索您的问题/问题/目标的许多清晰、简洁和特定的版本/措辞,带和不带您的特定字符串/名称,并阅读许多答案。将您发现的相关关键字添加到搜索中。如果您没有找到答案,请发布,使用 1 个变体搜索作为标签的标题和关键字。

标签: mysql laravel join


【解决方案1】:

您的原始 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 数组绑定到查询。原因是对于未知数量的规则很难做到这一点。但是,上面的代码应该会让你走上正轨。

【讨论】:

  • 当我为规则设置 1、2、3、4、5、6 或 3 或任何其他数字时,它会返回所有汽车,但我不想返回任何汽车。因为2,3,4是每辆车都有的规则,所以不应该包含在返回值中。
【解决方案2】:
$posts = App\Car::whereHas('rules', function ($query)use($ruleIds) {
    $query->whereNotIn('rule_id',  $ruleIds);
})->get();

【讨论】:

    【解决方案3】:

    我可以在@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 注入,我做了 for 循环。还有其他更好的方法吗?
    3. 在查询中有另一个选择,但我只想通过连接和简单的方式执行此操作。有没有其他方法可以得到这个?

    谢谢大家:)

    【讨论】:

      猜你喜欢
      • 2020-05-20
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-10-19
      • 2022-01-02
      • 1970-01-01
      • 2022-10-23
      相关资源
      最近更新 更多