【问题标题】:Need help converting nested join query to Laravel Eloquent需要帮助将嵌套连接查询转换为 Laravel Eloquent
【发布时间】:2016-04-01 15:15:30
【问题描述】:

需要一些帮助才能在 Laravel 中进行查询。

我已经在 laravel 之外尝试过这个查询并且它有效:

SELECT t.*
FROM
        stories AS t
    JOIN
        ( SELECT created_at
          FROM stories
          WHERE id = 126
        ) AS o
      ON t.created_at = o.created_at AND t.id > 126
      OR t.created_at < o.created_at
ORDER BY
    t.created_at DESC LIMIT 30;

解释:基本上它是分页所必需的,因为当用户转到下一页时,它会向他们显示在指定 id 之前创建的 30 个故事。当我按 created_at 对故事进行排序时,它们会变得随机,因此我需要在使用上述查询完成的特定行之后获取接下来的 30 行。 126是上一页最后一个故事的id,在实际代码中是一个变量。

所以当我尝试在 Laravel Eloquent 中使用它时,无论我做什么,我都无法让它工作。

我试过了

$result = App\Story::join(DB::table('stories AS last_story')->find($previous_last_post_id), function($join)
        {
            $join->on('stories.created_at', '=', 'last_story.created_at')
            ->where('stories.id', '>', 'last_story.id')
            ->orWhere('stories.created_at', '<', 'last_story.created_at');
        })
        ->get()

这给了我

Grammar.php 第 39 行中的 ErrorException:stdClass 类的对象无法转换为字符串

将子查询更改为

DB::table('stories AS last_story')->where('id', $previous_last_post_id)->get()

给我:

Grammar.php 第 39 行中的 ErrorException:数组到字符串的转换

放弃并尝试原始查询:

$result = DB::select("SELECT t.*
FROM
        stories AS t
    JOIN
        ( SELECT created_at
          FROM stories
          WHERE id = 126
        ) AS o
      ON t.created_at = o.created_at AND t.id > 126
      OR t.created_at < o.created_at
ORDER BY
    t.created_at DESC LIMIT 30")

但这给了我

e969125ed5dcf92ec33b84157c0eb37a 第 88 行中的 FatalErrorException:调用字符串上的成员函数 toFormattedDateString()

【问题讨论】:

    标签: mysql laravel laravel-5 eloquent laravel-5.1


    【解决方案1】:

    好的,所以我让它工作的唯一方法是:

    DB::select('
        SELECT t.id
        FROM
            stories AS t
        JOIN
            (
                SELECT created_at
                FROM stories
                WHERE id = ?
            ) AS o
        ON t.created_at = o.created_at AND t.id > ?
            OR t.created_at < o.created_at
        ORDER BY t.created_at DESC LIMIT 30
    ', [$previous_last_post_id, $previous_last_post_id]);
    

    我创建了一个几乎相同的雄辩查询:

    DB::table('stories')
        ->select('stories.id')
        ->join(DB::raw("(SELECT id, created_at FROM stories WHERE id = 126) as last_story"), function($join)
        {
            $join->on('stories.created_at', '=', 'last_story.created_at')
            ->where('stories.id', '>', 'last_story.id')
            ->orWhere('stories.created_at', '<', 'last_story.created_at');
        })->orderBy('stories.created_at', 'DESC')->take(30)->get();
    

    但它返回了错误的结果,所以我想这里不可能避免使用原始 sql。

    【讨论】:

      【解决方案2】:

      为什么不使用 laravel 内置的分页功能?

      $stories = App\Story::orderBy('created_at')->simplePaginate(30);
      

      它将使用 URL 参数跟踪当前页码。

      您可以使用以下命令打印上一个/下一个按钮:

      {!! $stories->render() !!}
      

      https://laravel.com/docs/5.1/pagination

      【讨论】:

      • 不知道 Laravel 实现了分页。这是一个很好的建议,但如果我添加 30 个新故事并且用户单击下一页按钮,他将看到他刚刚看到的相同故事,这就是我尝试使用上述查询的原因,以保存最后一个故事用户看到了,所以无论发生什么,他都会看到下一个故事。
      • 哦,那个特例。这是快速的内容创建。您可能不想对您很快拥有的大小的数据库使用雄辩的子查询。它会变慢。
      • 假设 created_at 与 id 列的顺序相同是否安全?通过最后一个 id 而不是最后一个时间戳进行查询可能会更快/更可预测。
      • 您已经查询过上一条记录。您不需要子查询,只需将已有的值作为参数放在 where 条件中即可。
      【解决方案3】:

      不要使用返回数组的get(),而是尝试使用first()

      【讨论】:

      • 你的意思是在子查询中? (使它成为 DB::table('stories AS last_story')->where('id', $previous_last_post_id)->first() )在 Grammar.php 第 39 行返回“ErrorException:无法转换类 stdClass 的对象串”。 :(
      猜你喜欢
      • 1970-01-01
      • 2021-07-27
      • 2016-04-27
      • 2021-08-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-07-28
      • 1970-01-01
      相关资源
      最近更新 更多