【问题标题】:Laravel Eloquent LEFT JOIN WHERE NULLLaravel Eloquent LEFT JOIN WHERE NULL
【发布时间】:2014-06-13 05:52:23
【问题描述】:

我正在尝试使用 Eloquent 在数据库种子期间执行以下查询:

SELECT
    *
FROM
    customers
LEFT JOIN
    orders
    ON customers.id = orders.customer_id
WHERE
    orders.customer_id IS NULL

这是我在 Eloquent 中的实现:

$c = Customer::leftJoin('orders', function($join) {
      $join->on('customers.id', '=', 'orders.customer_id');
    })
    ->whereNull('orders.customer_id')
    ->first();

虽然第一个查询总是返回完整的结果,但 Eloquent 等效项总是为除 customers 表的 emailphone 字段之外的所有内容返回空元素。我无法解释这一点,因为 CustomersOrders 模型都是工匠生成的骨架。

例如:

class Customer extends \Eloquent {

    // Add your validation rules here
    public static $rules = [
        // 'title' => 'required'
    ];

    // Don't forget to fill this array
    protected $fillable = [];

}

这是我 dd() 对种子(最初由 Faker 生成)的第一个 Eloquent 查询时输出的数组:

protected $original =>
  array(25) {
    'id' =>
    NULL
    'first_name' =>
    NULL
    'last_name' =>
    NULL
    'email' =>
    string(24) "luther.braun@example.org"
    'phone' =>
    string(17) "642.150.9176x5684"
    'address1' =>
    NULL
    'address2' =>
    NULL
    'city' =>
    NULL
    'state' =>
    NULL
    'county' =>
    NULL
    'district' =>
    NULL
    'postal_code' =>
    NULL
    'country' =>
    NULL
    'notes' =>
    NULL
    'created_at' =>
    NULL
    'updated_at' =>
    NULL
    'customer_id' =>
    NULL
    'total' =>
    NULL
}

【问题讨论】:

  • 此代码运行与您的 SQL 完全相同的查询

标签: php mysql laravel laravel-4 eloquent


【解决方案1】:

我会转储您的查询,以便您查看实际执行的 SQL 并了解它与您编写的内容有何不同。

您应该可以使用以下代码做到这一点:

$queries = DB::getQueryLog();
$last_query = end($queries);
var_dump($last_query);
die();

希望这能给你足够的信息,让你找出问题所在。

【讨论】:

  • 运行它并且查询是相同的。当我直接在 MySQL Workbench 中运行它们时,我得到了预期的结果。这告诉我问题在于 Laravel 处理检索数据的方式的某些方面。
  • 我刚刚意识到尚未创建的orders 表行中的NULL 字段正在覆盖customers 具有值的表中的值。 customersorders 表之间的唯一区别是orders 表没有emailphone 字段,因此不会覆盖该值。我以前从未见过这种行为。如何防止 Laravel 的 Eloquent 这样做?
【解决方案2】:

这可以通过指定特定表中所需的特定列名来解决,如下所示:

$c = Customer::leftJoin('orders', function($join) {
      $join->on('customers.id', '=', 'orders.customer_id');
    })
    ->whereNull('orders.customer_id')
    ->first([
        'customers.id',
        'customers.first_name',
        'customers.last_name',
        'customers.email',
        'customers.phone',
        'customers.address1',
        'customers.address2',
        'customers.city',
        'customers.state',
        'customers.county',
        'customers.district',
        'customers.postal_code',
        'customers.country'
    ]);

【讨论】:

  • 您还可以指定获取所有列,例如customers.*
  • 别名,例如customers.id as customer_id 也可以提高可读性。
【解决方案3】:

您还可以像这样在选择中指定列:

$c = Customer::select('*', DB::raw('customers.id AS id, customers.first_name AS first_name, customers.last_name AS last_name'))
->leftJoin('orders', function($join) {
  $join->on('customers.id', '=', 'orders.customer_id') 
})->whereNull('orders.customer_id')->first();

【讨论】:

    【解决方案4】:

    我会使用 laravel whereDoesntHave 来实现这一点。

    Customer::whereDoesntHave('orders')->get();
    

    【讨论】:

      【解决方案5】:

      虽然其他答案效果很好,但我想为您提供我经常使用的替代简短版本

      Customer::select('customers.*')
              ->leftJoin('orders', 'customers.id', '=', 'orders.customer_id')
              ->whereNull('orders.customer_id')->first();
      

      就像在laravel version 5.3 中一样,增加了一项功能,这将使您的工作更加简单,例如:

      Customer::doesntHave('orders')->get();
      

      【讨论】:

        【解决方案6】:
        use Illuminate\Database\Eloquent\Builder;
        
        $query = Customers::with('orders');
        $query = $query->whereHas('orders', function (Builder $query) use ($request) {
             $query = $query->where('orders.customer_id', 'NULL') 
        });
            $query = $query->get();
        

        【讨论】:

          猜你喜欢
          • 2018-12-04
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2014-08-19
          • 1970-01-01
          • 1970-01-01
          • 2021-11-29
          相关资源
          最近更新 更多