我有一个有许多订单的模型用户。订单有很多产品,其中有数据透视表订单产品。我不想在可能的情况下预加载和遍历订单。
我需要返回用户
我在2号上失败了。 在以下代码中,whereHas中的第一个查询是错误的。我不知道如何从哪里有引用用户的签名日期。如果要遍历集合中的用户,我可以使用($ query)来使用$ user,但是如何在不预载所有用户的情况下做到这一点?
return User::whereNotNull('signed_date')
->whereHas('orders', function ($query) {
$query->where('order_date', '<=', 'user.signed_date');
$query->whereHas('products', function ($q) {
$q->where('paid', false);
});
})
->get(['id','fname','lname', 'title', 'signed_date']);
如果可能的话,我想表达雄辩。如果这不可能,那么我将很高兴提供使用查询生成器/ sql解决此问题的提示。
答案 0 :(得分:0)
雄辩的查询构建器具有一个称为whereColumn('a', '<=', 'b')
的特殊功能,用于将列而不是列与值进行比较。由于查询生成器生成实际查询的方式,因此有必要使用此函数代替常规的where()
。您需要让查询生成器知道要传递列名而不是值,以正确转义和格式化查询字符串。
无论如何,似乎您也可以将以表名为前缀的列名传递给函数,从而使您可以跨表比较列:
$query->whereColumn('orders.order_date', '<=', 'users.signed_date')
之所以可行,是因为您在查询中使用了whereHas()
。您的查询基本上被翻译为:
SELECT id, fname, lname, title, signed_date
FROM users
WHERE signed_date NOT NULL
AND EXISTS (
SELECT 1
FROM orders
WHERE orders.order_date <= users.signed_date
AND EXISTS (
SELECT 1
FROM products
WHERE paid = 0
)
)
实际上,根本不需要将表名和whereColumn()
中的列名一起使用。但是,如果您要在另一张表上添加一列相同的列,查询可能会中断-因此恕我直言,在自定义查询中使用表名是个好习惯。
顺便说一句,它不能与with('relationship')
一起使用的原因是此函数导致一个附加查询,并且您显然无法比较查询之间的列。想象一下:
Order::with('user')->take(5)->get();
它将被翻译为以下内容:
SELECT *
FROM orders
LIMIT 5
SELECT *
FROM users
WHERE id IN (?, ?, ?, ?, ?)
其中五个?
将成为订单的user_id
。如果第一个查询返回的多个行具有相同的user_id
,则从users表中提取的行数当然会减少。
注意:所有查询仅是示例。
可能是因为查询生成器会根据数据库类型构建不同的查询和/或以不同的方式对它们进行转义(即,反引号中的列名称)。