【问题标题】:In Laravel Eloquent, how do I reference primary query in subquery在 Laravel Eloquent 中,如何在子查询中引用主查询
【发布时间】:2019-05-23 20:35:55
【问题描述】:

我有一个模型用户,它有很多订单。订单有很多产品,使用数据透视表 order-product。如果可能的话,我不想预加载和遍历订单。

我需要返回用户在哪里

  1. signed_date === 用户为真
  2. 订单的order_date 晚于用户的signed_date
  3. 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。如果这是不可能的,我会很高兴使用查询生成器/sql 解决这个问题的提示。

【问题讨论】:

  • whereHas 不是子查询。这是一个单独的查询,因此您无法真正将它们组合起来
  • 我不确定术语。如果不预加载所有用户,您将如何完成我的尝试?
  • @Namoshek 谢谢,它有效。请发表您之前的评论作为答案,我会接受。

标签: laravel eloquent laravel-query-builder


【解决方案1】:

Eloquent 查询构建器有一个名为whereColumn('a', '&lt;=', '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_ids。如果第一个查询返回多个具有相同 user_id 的行,那么从 users 表中获取的行数当然会减少。

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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-08-26
    • 1970-01-01
    • 2020-01-31
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多