Laravel Eloquent LEFT JOIN WHERE NULL
Posted
技术标签:
【中文标题】Laravel 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
表的 email
和 phone
字段之外的所有内容返回空元素。我无法解释这一点,因为 Customers
和 Orders
模型都是工匠生成的骨架。
例如:
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 完全相同的查询 【参考方案1】:我会转储您的查询,以便您查看实际执行的 SQL 并了解它与您编写的内容有何不同。
您应该可以使用以下代码做到这一点:
$queries = DB::getQueryLog();
$last_query = end($queries);
var_dump($last_query);
die();
希望这能给你足够的信息,让你找出问题所在。
【讨论】:
运行它并且查询是相同的。当我直接在 mysql Workbench 中运行它们时,我得到了预期的结果。这告诉我问题在于 Laravel 处理检索数据的方式的某些方面。 我刚刚意识到尚未创建的orders
表行中的NULL 字段正在覆盖customers
具有值的表中的值。 customers
和orders
表之间的唯一区别是orders
表没有email
或phone
字段,因此不会覆盖该值。我以前从未见过这种行为。如何防止 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();
【讨论】:
以上是关于Laravel Eloquent LEFT JOIN WHERE NULL的主要内容,如果未能解决你的问题,请参考以下文章
无法让 Laravel OrderBy 日期在 Eloquent 语句中工作
php Laravel 5 Eloquent CheatSheet #laravel #eloquent
php Laravel 5 Eloquent CheatSheet #laravel #eloquent
php Laravel 5 Eloquent CheatSheet #laravel #eloquent
php [Eloquent CheatSheet] Eloquent #laravel #eloquent的常见查询方法