web-dev-qa-db-fra.com

Rails Activerecord recherche (: tous,: ordre =>))

Il semble que je ne puisse pas utiliser l'option ActiveRecord :: Base.find: commandez plusieurs colonnes à la fois.

Par exemple, j'ai un modèle "Show" avec des colonnes de date et de présence.

Si je lance le code suivant:

@shows = Show.find(:all, :order => "date")

J'obtiens les résultats suivants:

[#<Show id: 7, date: "2009-04-18", attending: 2>, 
 #<Show id: 1, date: "2009-04-18", attending: 78>, 
 #<Show id: 2, date: "2009-04-19", attending: 91>, 
 #<Show id: 3, date: "2009-04-20", attending: 16>,
 #<Show id: 4, date: "2009-04-21", attending: 136>]

Si je lance le code suivant:

@shows = Show.find(:all, :order => "attending DESC")

[#<Show id: 4, date: "2009-04-21", attending: 136>,
 #<Show id: 2, date: "2009-04-19", attending: 91>,
 #<Show id: 1, date: "2009-04-18", attending: 78>,
 #<Show id: 3, date: "2009-04-20", attending: 16>,
 #<Show id: 7, date: "2009-04-18", attending: 2>]

Mais si je cours:

@shows = Show.find(:all, :order => "date, attending DESC")

OR

@shows = Show.find(:all, :order => "date, attending ASC")

OR

@shows = Show.find(:all, :order => "date ASC, attending DESC")

J'obtiens les mêmes résultats qu'en ne triant que par date:

 [#<Show id: 7, date: "2009-04-18", attending: 2>, 
 #<Show id: 1, date: "2009-04-18", attending: 78>, 
 #<Show id: 2, date: "2009-04-19", attending: 91>, 
 #<Show id: 3, date: "2009-04-20", attending: 16>,
 #<Show id: 4, date: "2009-04-21", attending: 136>]

Où comme, je veux obtenir ces résultats:

[#<Show id: 1, date: "2009-04-18", attending: 78>,
#<Show id: 7, date: "2009-04-18", attending: 2>, 
 #<Show id: 2, date: "2009-04-19", attending: 91>, 
 #<Show id: 3, date: "2009-04-20", attending: 16>,
 #<Show id: 4, date: "2009-04-21", attending: 136>]

Voici la requête générée à partir des journaux:

[4;35;1mUser Load (0.6ms)[0m   [0mSELECT * FROM "users" WHERE ("users"."id" = 1) LIMIT 1[0m
[4;36;1mShow Load (3.0ms)[0m   [0;1mSELECT * FROM "shows" ORDER BY date ASC, attending DESC[0m
[4;35;1mUser Load (0.6ms)[0m   [0mSELECT * FROM "users" WHERE ("users"."id" = 1) [0m

Enfin, voici mon modèle:

  create_table "shows", :force => true do |t|
    t.string   "headliner"
    t.string   "openers"
    t.string   "venue"
    t.date     "date"
    t.text     "description"
    t.datetime "created_at"
    t.datetime "updated_at"
    t.decimal  "price"
    t.time     "showtime"
    t.integer  "attending",   :default => 0
    t.string   "time"
  end

Qu'est-ce que je rate? Qu'est-ce que je fais mal?

PDATE: Merci pour toute votre aide, mais il semble que vous ayez tous été bloqués autant que moi. Ce qui a résolu le problème, c'était de changer de base de données. Je suis passé de la version par défaut de sqlite3 à mysql.

75

Je remarque que dans votre premier exemple, le simple : order => "date" , enregistrez 7 est trié avant l'enregistrement 1 . Cette commande correspond également à la manière dont vous voyez les résultats dans le tri multi-colonnes, que vous triiez ou non.

Cela semblerait logique si les dates ne sont pas exactement les mêmes et si la date de 7 est antérieure à la date de 1 . Au lieu de constater que les dates s sont exactement égales, procédez au tri par et assistez à , la requête constate que les dates ne sont pas égales et trie simplement par cela comme tous les autres enregistrements.

En parcourant le site, SQLite ne comprend pas de manière native les types de données DATE ou DATETIME et donne aux utilisateurs le choix entre des nombres à virgule flottante ou du texte qu'ils doivent analyser eux-mêmes. Est-il possible que la représentation littérale des dates dans la base de données ne soit pas exactement égale? La plupart des gens semblent avoir besoin de tiliser les fonctions de date pour que les dates se comportent comme prévu. Peut-être y at-il un moyen d’envelopper votre commande par colonne avec un fonction de date qui vous donnera quelque chose de concret à comparer, comme date (date) ASC, en assistant à DESC . Je ne suis pas sûr que la syntaxe fonctionne, mais c'est un domaine à considérer pour résoudre votre problème. J'espère que ça t'as aidé.

36
brism

Peut-être deux choses. D'abord,

Ce code est obsolète:

Model.find(:all, :order => ...)

devrait être:

Model.order(...).all

La recherche n'est plus prise en charge avec les commandes: all,: order et de nombreuses autres options.

Deuxièmement, vous avez peut-être eu un default_scope qui imposait un ordre avant d'appeler find sur Show.

Des heures passées à fouiller sur Internet m'ont amené à quelques articles utiles pour expliquer le problème:

45
thewillcole

Le problème est que date est un mot clé réservé de sqlite3 . J'ai eu un problème similaire avec time, également un mot clé réservé, qui a bien fonctionné dans PostgreSQL, mais pas dans sqlite3. La solution renomme la colonne.

Voir ceci: Sqlite3 activerecord: order => "le temps que DESC ne soit pas trié

14
oma

Je viens de rencontrer le même problème, mais je parviens à faire fonctionner ma requête dans SQLite comme ceci:

@shows = Show.order("datetime(date) ASC, attending DESC")

J'espère que cela pourrait aider quelqu'un à gagner du temps

4
Daniel Romero

n'est-ce pas seulement :order => 'column1 ASC, column2 DESC'?

3
Eimantas

Assurez-vous de vérifier directement le schéma au niveau de la base de données. Je me suis déjà fait avoir par le passé, où, par exemple, une migration avait été écrite initialement pour créer une colonne: datetime, puis je l'avais exécutée localement, puis je l'avais modifiée avec la date suivante: avant le déploiement. Ainsi, la base de données de chacun semble bonne sauf la mienne, et les bogues sont subtils.

3
gtd

C'est bien que vous ayez trouvé votre solution. Mais c'est un problème intéressant. Je l'ai essayé moi-même directement avec sqlite3 (sans passer par Rails) et je n'ai pas obtenu le même résultat. Pour moi, la commande est sortie comme prévu.

Ce que je vous suggère de faire si vous souhaitez continuer à creuser ce problème est de démarrer l'application de ligne de commande sqlite3 et de vérifier le schéma et les requêtes suivantes:

Cela vous montre le schéma: .schema

Et ensuite, exécutez simplement l'instruction select telle qu'elle apparaît dans les fichiers journaux: SELECT * FROM "shows" ORDER BY date ASC, attending DESC

De cette façon, vous voyez si:

  1. Le schéma ressemble à ce que vous voulez (cette date est en fait une date par exemple)
  2. Que la colonne de date contient en fait une date et non un horodatage (c'est-à-dire que vous n'avez pas une heure du jour qui dérange le tri)
2
Jimmy Stenke

Je comprends pourquoi Rails devs est allé avec sqlite3 pour une implémentation prête à l'emploi, mais MySQL est tellement plus pratique, à mon humble avis. Je réalise que cela dépend de ce que vous construisez = Rails app pour, mais la plupart des gens vont basculer le fichier database.yml par défaut de sqlite3 vers MySQL.

Je suis content que vous ayez résolu votre problème.

2
user59278

Cela pourrait aider aussi:

Post.order(created_at: :desc)
0
Maximus S