【问题标题】:laravel 5.3 - order results via whereIn mysqllaravel 5.3 - 通过 whereIn mysql 订购结果
【发布时间】:2017-05-29 07:30:19
【问题描述】:

我在这里查看了大多数其他解决方案,但它们似乎都不适合我。我有一张表,里面有大约 100K 行。

每一行都是来自 iot 设备的记录,其中包括该设备的唯一 ID。设备 id 可能有 100K 中的 10K 行。

Reading::whereIn('device_id', $ids)->orderBy('created_at',
 'DESC')->groupBy('device_id')->get()->

我能够提取我需要的 id 并将它们按上面查询的“device_id”分组在一起,但它会选择第一个结果而不是每个 id 的最后一个结果。

如何获取每个 id 的最新记录而不是最旧的记录?

我看过 laravel 集合和 reverse(), first(), latest();选项,但我仍然无法获得它

有什么想法吗?

更新

我能想到的最好的就是下面这个查询,它确实获取了每个 device_id 的最新记录

SELECT t1.* FROM readings t1 WHERE t1.id = (SELECT t2.id FROM readings
t2 WHERE t2.device_id = t1.device_id ORDER BY t2.id DESC LIMIT 1)

然后我将遍历这些结果并仅获取用户有权访问的记录。

不漂亮,但它现在工作。

如果有人真的想用雄辩的方式来做这件事,请回答

【问题讨论】:

    标签: php mysql laravel


    【解决方案1】:

    我终于把它整理好了。以下查询完全返回我在 laravel 中想要的内容。

    $sql = Reading::select('created_at', 'column1', 'column2', 'column3', 'column4', 'column5',
    'column6')->whereIn('device_id', ['0','0'])->toSql(); 
    
    // 0 is just "empty" value, it doesn't matter here yet
    
    $db = DB::connection()->getPdo();
    $query = $db->prepare($sql);
    
    // real ids im looking for
    
    $query->execute(array('ffvr5g6h', 'ccvl5f4rty'));
    
    
    $collection = collect($query);
    
    // change this to take ever (n) record 
    
    //$collection = $collection->every(100);
    $collection = $collection->groupBy('device_id');
    
     foreach ($collection as $collect) {
                    // process data
                   $end = $collect->last();
                   print_r($end);
                }
    

    上面的这个查询在大约半秒内查询了 100K 行,然后将其转换为 laravel 的集合,一次在集合中 i 按 id 分组,然后从该结果中获取最后一条记录。

    感谢所有试图提供帮助的人:)

    【讨论】:

      【解决方案2】:

      这是一个有点棘手的问题。一旦您用数据库术语重新构建问题,例如“获取 MySQL 查询中每个 id 的最大记录”,就很容易找到很多 SO 答案。

      这是一个关于 SO 的高评价示例:Retrieving the last record in each group

      在您更新的查询中,子查询实际上是针对我认为的每一行重新计算的。我们可以通过将读数加入自身来做得更好(查看上面的链接作为参考)

      SELECT r1.*
      FROM readings r1
        LEFT JOIN readings r2
          ON r2.device_id = r1.device_id
             AND r1.date_created < r2.date_created
      WHERE r2.device_id IS NULL # there is no row with a date_created greater than r1's
      ;
      

      device_id 和 date_created 上的索引是加快速度的简单第一步

      【讨论】:

      • 还记得您可以添加另一个 where 子句 AND r2.device_id IN ($ids),如果它们是数字,则添加 r2.device_id &gt; ($lowest_id) AND r2.device_id &lt; ($highest_id)。这可能比在代码中循环遍历结果更好。
      【解决方案3】:

      好的,我相信这可能会奏效,因为之前的尝试没有:

      $sub = Reading::orderBy('created_at','desc');
      
      return DB::table(DB::raw("({$sub->toSql()}) as sub"))
          ->whereIn('device_id', $ids)
          ->groupBy('device_id')
          ->get();
      

      您基本上运行的是“子查询”。因此,首先按您需要的顺序检索结果,然后运行第二个查询对它们进行分组。

      【讨论】:

      • 对此要小心。根据存储引擎和索引,订单可能会偏离
      【解决方案4】:

      我相信这应该可行?

      Reading::select('device_id', 'id', DB::raw('MAX(created_at) AS latest'))->whereIn('device_id', $ids)->orderBy('latest', 'DESC')->groupBy('device_id')->get();
      

      希望这会有所帮助!

      【讨论】:

      • 我在 Grammar.php 第 58 行得到这个“ErrorException:strtolower() 期望参数 1 是字符串,给定对象”
      • 你可能传入了一个对象的实例...给我们看看代码
      • 哪个代码 eitan?我的代码在上面,$ids 是一个数组
      • Grammar.php 第 58 行有什么内容?
      • 它是 laravel 默认安装的一部分,我已经查看了这个错误,它显然在 laravel 中发生了很多。试图找到解决办法。例如:laracasts.com/discuss/channels/eloquent/…
      猜你喜欢
      • 1970-01-01
      • 2012-05-23
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-03-06
      • 2020-01-05
      • 1970-01-01
      • 2020-11-02
      相关资源
      最近更新 更多