whereIn()はLaravelではEloquentやQuery Builderで良く使われます。特にwith()メソッドでは自動的に。今までこのクエリが返すレコードの順番はたいして気にしていなかったのですが、これはどうしたものか、という状況にぶち当たりました。

SQLというのは何も指定しない、つまりorderByを指定しないとSQLが返すレコードの順番は保証がありません。以下見てください。

>>> User::whereIn('id', [10,1,3])->pluck('id');

=> Illuminate\Support\Collection {#4581
     all: [
       1,
       3,
       10,
     ],
   }

直感的には、10,1,3を返すと思うところ、なぜかその順番にソートされていません。自動的にid順となっています。
多分、idがDBテーブルusersのプライマリーキーだから、その順で返している?

とにかく、orderByを明確に指定していないので返す順を頼りにすることはできません。

しかし、状況によっては指定した順番で返す必要あります。以下のように、お客さんが閲覧した商品の順番、最新閲覧した商品を一番左に持ってきます。

例えば、この商品のidがクッキーにその表示順でidを保存した場合は、その表示順で商品名や価格をDBから取得してくる必要あります。

この場合は、一般的はDBの項目の値に基づくorderByは使えません(もちろん、閲覧日時とかを別のDBテーブルに保存していないという仮定で)。

さて、どうしましょう?とリサーチすると便利なSQL関数がありました。
こんな感じで使います。

>>> User::whereIn('id', [10,1,3])->orderByRaw("FIELD(id,10,1,3)")->pluck('id');

=> Illuminate\Support\Collection {#4579
     all: [
       10,
       1,
       3,
     ],
   }

そして、これを先の商品の例に適応すると、こんな感じです。$productIdsには配列として、例えば[10,1,3]のような値があると仮定します。

Product::query()
    ->whereIn('product_id', $productIds)
    ->orderByRaw('FIELD(product_id, '.implode(',', $productIds).')')
    ->pluck('name', 'product_id');
メルマガ購読の申し込みはこちらから。

By khino