在 Laravel Eloquent 中,如何在子查询中引用主查询

In Laravel Eloquent, how do I reference primary query in subquery

我有一个有很多订单的模型用户。订单有很多产品,主元 table order-product。如果可能的话,我不想预加载和遍历订单。

我需要 return 用户

  1. signed_date === 用户
  2. 为真 订单
  3. order_date 在用户
  4. signed_date 之后
  5. order-product 显示产品尚未付款

我在 2 号上失败了。 在下面的代码中,whereHas 中的第一个查询是错误的。我不知道如何从 where has 中引用用户的签名日期。如果我在集合中遍历用户,我可以做类似 ($query) use $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']);

如果可能,我想使用 eloquent。如果这不可能,我很乐意提供使用查询 builder/sql 解决此问题的提示。

Eloquent 查询构建器有一个名为 whereColumn('a', '<=', 'b') 的特殊函数,用于比较列而不是列与值。由于查询构建器构建实际查询的方式,使用此函数而不是正常的 where() 是必要的。您需要让查询构建器知道您将传递列名而不是值,以便正确转义和格式化查询字符串。

无论如何,您似乎还可以将以 table 名称为前缀的列名称传递给函数,从而允许您比较 tables:

中的列
$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
      )
  )

实际上可能根本没有必要将 table 名称与 whereColumn() 中的列名称一起使用。但是,如果您在另一个 table 上添加同名的列,查询可能会中断 - 因此恕我直言,在自定义查询中使用 table 名称是一种很好的做法。


顺便说一句,这不能与 with('relationship') 一起工作的原因是这个函数会导致一个额外的查询,你显然不能跨查询比较列。想象一下:

Order::with('user')->take(5)->get();

它将被翻译成以下内容:

SELECT *
FROM orders
LIMIT 5

SELECT *
FROM users
WHERE id IN (?, ?, ?, ?, ?)

其中五个 ? 将是订单的 user_id。如果第一个查询 returns 具有相同 user_id 的多行,从用户 table 获取的行数当然会减少。

注意:所有查询仅是示例。可能是查询构建器根据数据库类型构建不同的查询 and/or 以不同方式转义它们(即反引号中的列名)。