2017-10-16 4 views
0

Quand je lance cette requête ...PG :: SyntaxError: erreur dans Rails clause where avec to_date

OnlineCourseRegistration.where("exam_completed_at.strftime('%m/%d/%Y').to_date + 360 = ?", Date.today) 

Je reçois cette erreur ...

2.3.0 :012 > OnlineCourseRegistration.where("exam_completed_at.strftime('%m/%d/%Y').to_date = ?", Date.today) 
    OnlineCourseRegistration Load (0.5ms) SELECT "class_registrations".* FROM "class_registrations" INNER JOIN "course_classes" ON "course_classes"."id" = "class_registrations"."course_class_id" INNER JOIN "courses" ON "courses"."id" = "course_classes"."course_id" INNER JOIN "users" ON "users"."id" = "class_registrations"."user_id" WHERE (course_classes.class_type = 'online') AND (exam_completed_at.strftime('%m/%d/%Y').to_date = '2017-10-16') 
PG::SyntaxError: ERROR: syntax error at or near "." 
LINE 1: ...line') AND (exam_completed_at.strftime('%m/%d/%Y').to_date =... 
                  ^
: SELECT "class_registrations".* FROM "class_registrations" INNER JOIN "course_classes" ON "course_classes"."id" = "class_registrations"."course_class_id" INNER JOIN "courses" ON "courses"."id" = "course_classes"."course_id" INNER JOIN "users" ON "users"."id" = "class_registrations"."user_id" WHERE (course_classes.class_type = 'online') AND (exam_completed_at.strftime('%m/%d/%Y').to_date = '2017-10-16') 
ActiveRecord::StatementInvalid: PG::SyntaxError: ERROR: syntax error at or near "." 
LINE 1: ...line') AND (exam_completed_at.strftime('%m/%d/%Y').to_date =... 
                  ^
: SELECT "class_registrations".* FROM "class_registrations" INNER JOIN "course_classes" ON "course_classes"."id" = "class_registrations"."course_class_id" INNER JOIN "courses" ON "courses"."id" = "course_classes"."course_id" INNER JOIN "users" ON "users"."id" = "class_registrations"."user_id" WHERE (course_classes.class_type = 'online') AND (exam_completed_at.strftime('%m/%d/%Y').to_date = '2017-10-16') 
    from /Users/marklocklear/.rvm/gems/ruby-2.3.0/gems/activerecord-4.0.2/lib/active_record/connection_adapters/postgresql_adapter.rb:774:in `async_exec' 
    from /Users/marklocklear/.rvm/gems/ruby-2.3.0/gems/activerecord-4.0.2/lib/active_record/connection_adapters/postgresql_adapter.rb:774:in `exec_no_cache' 
    from /Users/marklocklear/.rvm/gems/ruby-2.3.0/gems/activerecord-4.0.2/lib/active_record/connection_adapters/postgresql/database_statements.rb:138:in `block in exec_query' 
    from /Users/marklocklear/.rvm/gems/ruby-2.3.0/gems/activerecord-4.0.2/lib/active_record/connection_adapters/abstract_adapter.rb:435:in `block in log' 
    from /Users/marklocklear/.rvm/gems/ruby-2.3.0/gems/activesupport-4.0.2/lib/active_support/notifications/instrumenter.rb:20:in `instrument' 
    from /Users/marklocklear/.rvm/gems/ruby-2.3.0/gems/activerecord-4.0.2/lib/active_record/connection_adapters/abstract_adapter.rb:430:in `log' 
    from /Users/marklocklear/.rvm/gems/ruby-2.3.0/gems/activerecord-4.0.2/lib/active_record/connection_adapters/postgresql/database_statements.rb:137:in `exec_query' 
    from /Users/marklocklear/.rvm/gems/ruby-2.3.0/gems/activerecord-4.0.2/lib/active_record/connection_adapters/postgresql_adapter.rb:891:in `select' 
    from /Users/marklocklear/.rvm/gems/ruby-2.3.0/gems/activerecord-4.0.2/lib/active_record/connection_adapters/abstract/database_statements.rb:24:in `select_all' 
    from /Users/marklocklear/.rvm/gems/ruby-2.3.0/gems/activerecord-4.0.2/lib/active_record/connection_adapters/abstract/query_cache.rb:63:in `select_all' 
    from /Users/marklocklear/.rvm/gems/ruby-2.3.0/gems/activerecord-4.0.2/lib/active_record/querying.rb:36:in `find_by_sql' 
    from /Users/marklocklear/.rvm/gems/ruby-2.3.0/gems/activerecord-4.0.2/lib/active_record/relation.rb:585:in `exec_queries' 
    from /Users/marklocklear/.rvm/gems/ruby-2.3.0/gems/activerecord-4.0.2/lib/active_record/relation.rb:471:in `load' 
    from /Users/marklocklear/.rvm/gems/ruby-2.3.0/gems/activerecord-4.0.2/lib/active_record/relation.rb:220:in `to_a' 
    from /Users/marklocklear/.rvm/gems/ruby-2.3.0/gems/activerecord-4.0.2/lib/active_record/relation.rb:598:in `exec_queries' 
    from /Users/marklocklear/.rvm/gems/ruby-2.3.0/gems/activerecord-4.0.2/lib/active_record/relation.rb:471:in `load' 
    from /Users/marklocklear/.rvm/gems/ruby-2.3.0/gems/activerecord-4.0.2/lib/active_record/relation.rb:220:in `to_a' 
    from /Users/marklocklear/.rvm/gems/ruby-2.3.0/gems/activerecord-4.0.2/lib/active_record/relation.rb:573:in `inspect' 
    from /Users/marklocklear/.rvm/gems/ruby-2.3.0/gems/railties-4.0.2/lib/rails/commands/console.rb:90:in `start' 
    from /Users/marklocklear/.rvm/gems/ruby-2.3.0/gems/railties-4.0.2/lib/rails/commands/console.rb:9:in `start' 
    from /Users/marklocklear/.rvm/gems/ruby-2.3.0/gems/railties-4.0.2/lib/rails/commands.rb:62:in `<top (required)>' 
    from bin/rails:4:in `require' 

J'ai essayé de changer les citations et des backticks, mais pas de chance.

+2

Je ne sais pas ruby.Mais strftime est une fonction ruby ​​et vous essayez de l'utiliser comme une fonction postgresql. –

+0

Si vous cherchez un moyen Rails: 'OnlineCourseRegistration.where ({exam_completed_at: (Time.now.midnight - 361.day) .. (Time.now.midnight - 360.day)})' – ninjarails

Répondre

0

Après beaucoup de chasse à la baleine et des grincements de dents, je pense J'ai la requête Je cherche. Je suis encore en train de tester, mais jusqu'à présent cela semble fonctionner.

Juste pour ajouter un peu de contexte à la requête d'origine que j'essayais de lancer. En anglais courant, j'essayais de trouver des documents dont la date exam_completed_at est d'un an avant la date d'aujourd'hui. Dit d'une autre façon que je cherche des dossiers dont exam_completed_at date est la date d'aujourd'hui moins 360 (ou un an).

Voici ce que je suis venu avec:

OnlineCourseRegistration.where("exam_completed_at BETWEEN ? AND ?", DateTime.now.beginning_of_day - 1.year, DateTime.now.end_of_day - 1.year) 

Comme un contrôle de santé mentale, consultez ce disque:

2.3.0 :276 > OnlineCourseRegistration.find 14340 
D, [2017-10-17T10:01:54.622455 #35257] DEBUG -- : OnlineCourseRegistration Load (0.9ms) SELECT "class_registrations".* FROM "class_registrations" INNER JOIN "course_classes" ON "course_classes"."id" = "class_registrations"."course_class_id" INNER JOIN "courses" ON "courses"."id" = "course_classes"."course_id" INNER JOIN "users" ON "users"."id" = "class_registrations"."user_id" WHERE (course_classes.class_type = 'online') AND "class_registrations"."id" = $1 LIMIT 1 [["id", 14340]] 
=> #<OnlineCourseRegistration id: 14340, cart_id: 15093, user_id: 7090, course_class_id: 681, created_at: "2017-09-05 15:19:23", updated_at: "2017-10-17 13:29:08", exam_attempts: 0, exam_completed_at: "2016-10-17 13:29:03", evaluation_completed_at: nil, status: "Active", score: nil, add_extension: false, retest_cart_id: nil, retest_purchased_at: nil> 

... et notez la date de exam_completed_at est 2016-10-17 13:29:03. Maintenant, quand j'exécute la requête, je reçois le même enregistrement retourné:

2.3.0 :275 > OnlineCourseRegistration.where("exam_completed_at BETWEEN ? AND ?", DateTime.now.beginning_of_day - 1.year, DateTime.now.end_of_day - 1.year) 
D, [2017-10-17T09:59:27.832326 #35257] DEBUG -- : OnlineCourseRegistration Load (2.2ms) SELECT "class_registrations".* FROM "class_registrations" INNER JOIN "course_classes" ON "course_classes"."id" = "class_registrations"."course_class_id" INNER JOIN "courses" ON "courses"."id" = "course_classes"."course_id" INNER JOIN "users" ON "users"."id" = "class_registrations"."user_id" WHERE (course_classes.class_type = 'online') AND (exam_completed_at BETWEEN '2016-10-17 04:00:00.000000' AND '2016-10-18 03:59:59.000000') 
=> #<ActiveRecord::Relation [#<OnlineCourseRegistration id: 14340, cart_id: 15093, user_id: 7090, course_class_id: 681, created_at: "2017-09-05 15:19:23", updated_at: "2017-10-17 13:29:08", exam_attempts: 0, exam_completed_at: "2016-10-17 13:29:03", evaluation_completed_at: nil, status: "Active", score: nil, add_extension: false, retest_cart_id: nil, retest_purchased_at: nil>, #<OnlineCourseRegistration id: 14267, cart_id: 15004, user_id: 7069, course_class_id: 681, created_at: "2017-07-15 22:06:06", updated_at: "2017-10-17 13:49:17", exam_attempts: 1, exam_completed_at: "2016-10-17 13:49:11", evaluation_completed_at: "2017-07-20 23:59:01", status: "Completed", score: "87", add_extension: false, retest_cart_id: nil, retest_purchased_at: nil>]> 
0

Vous avez votre SQL et ruby ​​confondus.

exam_completed_at.strftime('%m/%d/%Y').to_date est le code Ruby mais vous l'avez exécuté en SQL.

Une façon de fixer et d'utiliser plus jolie AREL (en supposant exam_completed_at est le champ de base de données pour filtrer et non une variable locale) avec une plage de dates:

where(
    exam_completed_at: 
    (Date.today.beginning_of_day - 360.days)..(Date.today.end_of_day - 360.days) 
) 
0

Essayez ceci:

OnlineCourseRegistration.where("(created_at - current_timestamp) < interval '360 day'") 
+0

Le problème est que ne utilisera pas index sur 'exam_completed_at'. est mieux utiliser 'where (exam_completed_at = CURRENT_DATE - INTERVAL '12 mois ')' –

+1

D'accord avec l'index mais votre syntaxe n'est pas correcte. – ninjarails

1

Dans postgresql vous avez to_char fonction pour convertir une date en chaîne.

to_char(timestamp, text) 

Mais vous avez besoin d'un type d'horodatage de sorte que vous devez utiliser current_timestamp

Donc, pour obtenir l'horodatage d'il y a 360 jours que vous utilisez:

current_timestamp - interval '360 days' 

Pour obtenir une chaîne avec cette date:

SQL DEMO

to_char(current_timestamp - interval '360 days', 'MM/dd/YYYY') 

Ceci génère une valeur constante qui peut donc être utilisée avec un index.

donc votre code Ruby doit être:

.where("exam_completed_at = to_char(current_timestamp - interval '360 days', 'MM/dd/YYYY') 
+0

Je ne pense pas que cela fonctionnerait. Il compare l'horodatage complet alors que nous avons seulement besoin de comparer l'intervalle de jours. – ninjarails

+0

@MingJin Avez-vous vu la démo? Cet horodatage convertit en chaîne. Et parce que OP utilise 'strftime' nous avons besoin de convertir l'heure actuelle en chaîne et c'est ce que' to_char' fait –

+0

Comprendre. mais soulèvera toujours une erreur d'opérateur, car il compare horodatage avec la date. – ninjarails