7

Estoy trabajando en la migración de una base de datos heredada en mi aplicación Rails (3.2.3). La base de datos original viene con bastantes consultas SQL largas para informes. Por ahora, lo que me gustaría hacer es utilizar las consultas sql en la aplicación Rails y luego una a una (cuando el tiempo lo permita) intercambiar las consultas SQL a las consultas "Rails" correctas.¿Cómo usar consultas sql sin procesar en la aplicación Rails 3?

tengo un modelo clínico y el controlador tiene el siguiente código:

@clinical_income_by_year = Clinical.find_all_by_sql(SELECT date_format(c.transactiondate,'%Y') as Year, 
               date_format(c.transactiondate,'%b') as Month, 
               sum(c.LineBalance) as "Income" 
               FROM clinical c 
               WHERE c.Payments = 0 AND c.LineBalance <> 0 
               AND c.analysiscode <> 213 
               GROUP BY c.MonthYear;) 

Sin embargo, cuando corro ese código me sale un par de errores que se pueden hacer con el formato.

Started GET "/clinicals" for 127.0.0.1 at 2012-04-29 18:00:45 +0100 

SyntaxError (/Users/dannymcclelland/Projects/premvet/app/controllers/clinicals_controller.rb:6: syntax error, unexpected tIDENTIFIER, expecting ')' 
...rmat(c.transactiondate,'%Y') as Year, 
...        ^
/Users/dannymcclelland/Projects/premvet/app/controllers/clinicals_controller.rb:7: syntax error, unexpected tIDENTIFIER, expecting keyword_end 
...rmat(c.transactiondate,'%b') as Month, 
...        ^
/Users/dannymcclelland/Projects/premvet/app/controllers/clinicals_controller.rb:8: syntax error, unexpected tIDENTIFIER, expecting keyword_end 
...   sum(c.LineBalance) as "Income" 
...        ^
/Users/dannymcclelland/Projects/premvet/app/controllers/clinicals_controller.rb:10: syntax error, unexpected tCONSTANT, expecting keyword_end 
...  WHERE c.Payments = 0 AND c.LineBalance <> 0 
...        ^
/Users/dannymcclelland/Projects/premvet/app/controllers/clinicals_controller.rb:10: syntax error, unexpected '>' 
...yments = 0 AND c.LineBalance <> 0 
...        ^
/Users/dannymcclelland/Projects/premvet/app/controllers/clinicals_controller.rb:11: syntax error, unexpected '>' 
...   AND c.analysiscode <> 213 
...        ^

¿Hay algo que deba hacer en la consulta sql antes de importarlo al controlador? Aunque es posible que haya algún problema con la consulta (fue escrita hace bastante tiempo), funciona como se esperaba cuando se ejecuta directamente dentro de la base de datos. Devuelve una matriz como esta:

---------------------------------------------- 
| Year  | Month  |  Income  | 
---------------------------------------------- 
---------------------------------------------- 
| 2012  | January | 20,000  | 
| 2012  | February | 20,000  | 
| 2012  | March  | 20,000  | 
| 2012  | April  | 20,000  | 
---------------------------------------------- 
etc.. 

¡Cualquier ayuda, consejo o sugerencias generales se agradecerán!

Estoy leyendo a través de http://guides.rubyonrails.org/active_record_querying.html tratando de convertir la consulta sql en una consulta correcta de Rails.

Hasta ahora han igualado la segunda a la última línea:

AND c.analysiscode <> 213 

con

@clinical_income_by_year = Clinical.where("AnalysisCode != 213") 

pasos de bebé!

ACTUALIZACIÓN

Tengo el filtrado ordenados ahora, gracias al sitio de raíles de guía, pero estoy atascado en la parte agrupación y la suma de la consulta SQL. Tengo el siguiente hasta el momento:

@clinical_income_by_year = Clinical.where("AnalysisCode != 213 AND Payments != 0 AND LineBalance != 0").page(params[:page]).per_page(15) 

estoy luchando para construir en las siguientes dos líneas de la consulta SQL:

sum(c.LineBalance) as "Income" 

y

GROUP BY c.MonthYear;) 

Mi código de la vista se parece esto:

<% @clinical_income_by_year.each do |clinical| %> 
    <tr> 
    <td><%= clinical.TransactionDate.strftime("%Y") %></td> 
    <td><%= clinical.TransactionDate.strftime("%B") %></td> 
    <td><%= Clinical.sum(:LineBalance) %></td> 
    </tr>  
    <% end %> 
</table> 
    <%= will_paginate @clinical_income_by_year %> 

Respuesta

14

The R uby analizador no entiende SQL, es necesario utilizar una cadena:

@clinical_income_by_year = Clinical.find_by_sql(%q{ ... }) 

me gustaría recomendar el uso %q o %Q (si necesita interpolación) de este modo que usted no tiene que preocuparse por comillas incrustadas tanto.También debe pasar eso a un método de clase en el modelo para evitar que sus controladores se preocupen por cosas que no les interesan, esto también le dará fácil acceso a connection.quote y amigos para que pueda usar correctamente la interpolación de cadenas:

find_by_sql(%Q{ 
    select ... 
    from ... 
    where x = #{connection.quote(some_string)} 
}) 

Además, el punto y coma en su SQL:

GROUP BY c.MonthYear;}) 

no es necesario. Algunas bases de datos lo dejarán pasar, pero debe deshacerse de él de todos modos.

Dependiendo de su base de datos, los identificadores (nombres de tabla, columnas, ...) deberían ser insensibles a las mayúsculas y minúsculas (a menos que alguna persona odiosa los citara cuando se crearon). hacer que las cosas se adapten mejor a Rails.

También tenga en cuenta que a algunas bases de datos no les gustará GROUP BY porque tiene columnas en su SELECT que no están agregadas o agrupadas por lo que existe ambigüedad sobre qué c.transactiondate usar para cada grupo.


Una más "Railsy" versión de la consulta sería algo como esto:

@c = Clinical.select(%q{date_format(transactiondate, '%Y') as year, date_format(transactiondate, '%b') as month, sum(LineBalance) as income}) 
      .where(:payments => 0) 
      .where('linebalance <> ?', 0) 
      .where('analysiscode <> ?', 213) 
      .group(:monthyear) 

entonces se podría hacer cosas como esta:

@c.each do |c| 
    puts c.year 
    puts c.month 
    puts c.income 
end 

para acceder a los resultados. También podría simplificar un poco empujando el planchado de la fecha en Rubí:

@c = Clinical.select(%q{c.transactiondate, sum(c.LineBalance) as income}) 
      .where(:payments => 0) 
      .where('linebalance <> ?', 0) 
      .where('analysiscode <> ?', 213) 
      .group(:monthyear) 

Luego se separan c.transactiondate en Ruby en lugar de llamar c.year y c.month.

+0

Como he comenzado la ruta de conversión de la consulta sql a una consulta de Rails, ¿recomendaría continuar o está utilizando las consultas sql algo común dentro de los modelos y controladores? – dannymcc

+1

@dannymcc: el uso de los métodos Rails generalmente se recomienda pero a veces es necesario SQL, si usó características de la base de datos "avanzadas" como procedimientos almacenados, funciones de ventana, tablas derivadas, CTE, etc., entonces tendrá que escribir una gran cantidad de materias primas SQL para hacer el trabajo; si todas sus consultas son simples 'select * from t1 where ...' questions, entonces probablemente sea mejor utilizar los métodos de ActiveRecord. Es un llamado a juicio, use lo que sea más claro para usted y las personas que mantienen su código. –

+0

Creo que el uso de los métodos de ActiveRecord es más claro para mí al leerlos, ¡pero escribirlos es tan complejo como escribirme consultas sql sin procesar para mí! Gracias por el consejo. – dannymcc

Cuestiones relacionadas