Sélectionnez la dernière ligne du tableau

163

Je souhaite récupérer le dernier fichier inséré dans ma table. Je sais que la méthode first()existe et vous fournit le premier fichier du tableau mais je ne sais pas comment obtenir le dernier insert.

Carlos Suñol
la source
Voir aussi stackoverflow.com/questions/33321447/… Comment trier une relation existante (hasMany)
Tarek Adam
Ceci est pour toute personne demandant et répondant à propos de Laravel. N'oubliez pas qu'il est important de spécifier de quelle version de Laravel vous parlez. En général, les versions 4 et 5 présentent des différences et les anciennes versions aussi.
Heroselohim

Réponses:

224

Vous devrez classer par le même champ que vous commandez maintenant, mais en ordre décroissant. Par exemple, si vous avez un horodatage lorsque le téléchargement a été appelé upload_time, vous feriez quelque chose comme ceci;

Pour Pre-Laravel 4

return DB::table('files')->order_by('upload_time', 'desc')->first();

Pour Laravel 4 et plus

return DB::table('files')->orderBy('upload_time', 'desc')->first();

Pour Laravel 5.7 et versions ultérieures

return DB::table('files')->latest('upload_time')->first();

Cela ordonnera les lignes de la table des fichiers par heure de téléchargement, ordre décroissant et prendra la première. Ce sera le dernier fichier téléchargé.

Joachim Isaksson
la source
15
Pour Laravel 4, cela devrait être orderBy, pasorder_by
Jared Eitnier
9
Lorsque vous utilisez ORM, c'est une manière correcte:User::orderby('created_at', 'desc')->first();
Cas Bloem
1
Laravel 5.x =orderBy('created_at', 'desc')
0x1ad2
9
Pourquoi utilisez-vous la colonne created_at? Beaucoup plus rapide à utiliser l'ID de clé primaire. Laravel 5.x Files::orderBy(id', 'desc')->first();Trier par date fonctionne plus longtemps car la date est une chaîne et probablement non indexée. Alors que la clé primaire est indexée et fonctionne très rapidement. Même si created_at est indexé, il s'agit d'une chaîne indexée et non de INT en cas de primaire. La chaîne d'index a moins de performances.
KorbenDallas
4
Le commentaire @KorbenDallas devrait être la réponse car parfois orderBy('created_at', 'desc')ne vous donne pas la dernière ligne. Exemple: 3 lignes peuvent avoir exactement la même valeur TIMESTAMP et avec orderBy('created_at', 'desc')vous obtiendrez la première des 3 (qui n'est pas nécessairement la dernière ligne)
viery365
111

Utilisez la dernière portée fournie par Laravel hors de la boîte.

Model::latest()->first();

De cette façon, vous ne récupérez pas tous les enregistrements. Un raccourci plus agréable pour orderBy.

pseudo
la source
7
Notez que cette méthode utilise la created_atcolonne auto-générée ($timestamps = true)dans le modèle, mais peut être désactivée à souhait pour que vous ayez une erreur si non définie
Plotisateur
J'utilise Laravel 5.7 et j'essaie de le faire sur un modèle récupère toujours tous les enregistrements pour moi.
CJ Dennis
1
Notez que si vous avez plusieurs enregistrements ajoutés dans la même seconde, l'heure created_at sera la même pour ces enregistrements et par conséquent, l'enregistrement renvoyé par latest () peut ne pas être l'enregistrement que vous attendez.
F3CP
Notez que vous n'avez pas besoin d'une colonne «created_at». Vous pouvez spécifier à partir de quelle colonne vous voulez la dernière. Par exemple: Model :: latest ('dateColumn') -> first ();
Tom
Cela peut ne pas obtenir la dernière ligne réelle si deux lignes sont insérées dans un délai de 1 seconde (cela a en fait causé des problèmes dans les tests unitaires).
chili
75

Vous n'avez jamais mentionné si vous utilisiez Eloquent, l'ORM par défaut de Laravel ou non. Dans le cas où vous l'êtes, disons que vous voulez obtenir la dernière entrée d'une table User, par created_at, vous pourriez probablement faire comme suit:

User::orderBy('created_at', 'desc')->first();

Tout d'abord, il classe les utilisateurs par champ created_at, par ordre décroissant, puis il prend le premier enregistrement du résultat.

Cela vous renverra une instance de l'objet User, pas une collection. Bien sûr, pour utiliser cette alternative, vous devez avoir un modèle User, étendant la classe Eloquent. Cela peut sembler un peu déroutant, mais il est vraiment facile de commencer et ORM peut être vraiment utile.

Pour plus d'informations, consultez la documentation officielle qui est assez riche et bien détaillée.

Luis Milanese
la source
42

Pour obtenir les détails du dernier enregistrement

  1. Model::all()->last(); ou
  2. Model::orderBy('id', 'desc')->first();

Pour obtenir l'identifiant du dernier enregistrement

  1. Model::all()->last()->id; ou
  2. Model::orderBy('id', 'desc')->first()->id;
Haseena PA
la source
14

Les collections Laravel ont la dernière méthode

Model::all() -> last(); // last element 
Model::all() -> last() -> pluck('name'); // extract value from name field. 

C'est la meilleure façon de procéder.

mdamia
la source
16
Je voulais juste souligner que la all()méthode charge en fait tous les éléments. Cela ne fonctionnera pas sur une table avec des millions d'enregistrements.
Steven Jeffries
1
En plus du commentaire de Steven Jeffries, je voudrais souligner que l'appel last()renvoie une seule instance Eloquent et non une collection, et appeler pluck()cela équivaut à appeler Model::all()->pluck('name'), donc renvoyer l' nameattribut de toutes les lignes de la table
ivcandela
5
Cette méthode est pire en fait. Vous récupérez le dernier brut en utilisant l'exécution PHP au lieu de le faire au niveau de la base de données. Et si la table contient des millions de matières premières, alors vous savez à quel point elle peut être inefficace?
Bhaskar Dabhi
C'est la meilleure façon de procéder. - Non! Cela n'a jamais été, ne le sera jamais. Vous chargez toutes les lignes au lieu de celle dont vous avez besoin.
René Roth
11

Essaye ça :

Model::latest()->get();
Mark-Hero
la source
1
Cela renverra plusieurs lignes. Il a besoin d'une seule rangée. first () l'aidera avec la clause orderBy ().
Tahir Afridi
Cela peut ne pas obtenir la dernière ligne réelle si deux lignes sont insérées dans un délai de 1 seconde (cela a en fait causé des problèmes dans les tests unitaires).
chili
1
Sur une grande table, cela provoquera une exception de mémoire insuffisante car, comme @TahirAfridi l'a mentionné, cela chargera toutes les lignes en mémoire.
Rihards
6

Vous pouvez utiliser la dernière portée fournie par Laravel avec le champ que vous souhaitez filtrer, disons qu'il sera trié par ID, puis:

Model::latest('id')->first();

Ainsi, vous pouvez éviter de commander par created_atchamp par défaut chez Laravel.

tiaguinhow
la source
5

Pour obtenir les détails du dernier enregistrement, utilisez le code ci-dessous:

Model::where('field', 'value')->get()->last()
Jimuel Palaca
la source
Ne l'utilisez pas. C'est une très mauvaise pratique car il existe une dernière portée (), elle fournit un accès direct à la dernière ligne insérée.
Working Pig
3

Une autre façon sophistiquée de le faire dans Laravel 6.x (Incertain mais doit également fonctionner pour 5.x):

DB::table('your_table')->get()->last();

Vous pouvez également accéder aux champs:

DB::table('your_table')->get()->last()->id;

Serviette
la source
Fonctionne aussi pour moi dans Laravel 5.8, je viens de poster la réponse avant de voir la vôtre
Dazzle
1
Une petite explication sur la façon dont laravel fait cela dans les coulisses et pourquoi cela est dangereux pour un grand ensemble de données, la get()méthode récupérera tout your_tableet générera une collection et la last()méthode obtiendra le dernier élément de cette collection. Donc, vous aurez déjà toutes les données de la table chargées sur votre mémoire (mauvaise). Vous devez simplement utiliser `DB :: table ('items') -> latest () -> first ();` derrière la scène, il exécute `orderBy ($ column, 'desc')` et récupère le premier enregistrement.
Anuj Shrestha le
2

Model($where)->get()->last()->id

Éblouir
la source
1

Si vous recherchez la ligne réelle que vous venez d'insérer avec Laravel 3 et 4 lorsque vous effectuez une action saveou createsur un nouveau modèle comme:

$user->save();

-ou-

$user = User::create(array('email' => '[email protected]'));

puis l'instance de modèle insérée sera retournée et pourra être utilisée pour d'autres actions telles que la redirection vers la page de profil de l'utilisateur qui vient d'être créé.

La recherche du dernier enregistrement inséré fonctionne sur un système à faible volume fonctionnera presque tout le temps, mais si jamais vous devez insérer des insertions en même temps, vous pouvez finir par interroger pour trouver le mauvais enregistrement. Cela peut vraiment devenir un problème dans un système transactionnel où plusieurs tables doivent être mises à jour.

bloggidy
la source
1

D'une manière ou d'une autre, tout ce qui précède ne semble pas fonctionner pour moi dans laravel 5.3, j'ai donc résolu mon propre problème en utilisant:

Model::where('user_id', '=', $user_id)->orderBy('created_at', 'desc')->get();

j'espère pouvoir renflouer quelqu'un.

Le mec mort
la source
1

Utilisez- Model::where('user_id', $user_id)->latest()->get()->first(); le ne retournera qu'un seul enregistrement, s'il n'est pas trouvé, il retournera null. J'espère que cela aidera.

风声 猎猎
la source
0

Si la table a un champ de date, c'est ( User::orderBy('created_at', 'desc')->first();) la meilleure solution, je pense. Mais il n'y a pas de champ de date, Model ::orderBy('id', 'desc')->first()->id;c'est la meilleure solution, j'en suis sûr.

Wang Xin
la source
0

soyez conscient que last(), latest()ne sont pas déterministes si vous recherchez un enregistrement séquentiel ou événement / ordonné. Les derniers enregistrements / récents peuvent avoir exactement le même created_athorodatage, et que vous récupérez n'est pas déterministe. Alors fais orderBy(id|foo)->first(). D'autres idées / suggestions sur la façon d'être déterministe sont les bienvenues.

mangonights
la source