Sql group by


#1

Tengo definida una tabla son la siguiente estructura:

table: diario
cuenta string(10)
debe numeric
haber numeric

Estoy probando de ejecutar una consulta SQL que haga un SUM y un GROUP
BY

SELECT cuenta, sum(debe) sumdebe, sum(haber) sumhaber from diario group
by cuenta

Para ejecutar este SQL he escrito el siguiente codigo:

@cuentas=diario.find_by_sql(“SELECT cuenta, sum(debe) sumdebe,
sum(haber) sumhaber from diario group by cuenta”)

y he visto que el resultado de la SQL se mapea sobre la definicion de la
tabla. Es decir, solo me devuelve la columna cuenta.

En cambio si ejecuto:
@cuentas=diario.find_by_sql(“SELECT cuenta, sum(debe) debe, sum(haber)
haber from diario group by cuenta”)
me devuelve las 3 columnas.

A raiz de este problema, se me han planteado 2 preguntas:
a) Como se puede hacer SQL libres sin pasar por el mapping del modelo?
b) Como es posible saber el nombre de las columnas que han retornado un
SQL?

Gracias


#2

Hola Rafa :wink:

A raiz de este problema, se me han planteado 2 preguntas:
a) Como se puede hacer SQL libres sin pasar por el mapping del modelo?

Cundo haces un find_by_sql se ejecuta la sentencia SQL directamente, con
lo
cual al mapping del modelo no deberia afectarte

b) Como es posible saber el nombre de las columnas que han retornado un
SQL?

El resultado de un find es un array de objetos, si lo recorres puedes
hacer
un respond_to? para ver si existe ese atributo

@cuentas.each do |cuenta|
if cuenta.respond_to? :sumdebe

end
end


#3

2009/3/26 Rafa C. removed_email_address@domain.invalid:

=> [#<Diario cuenta: “430017”, debe:
#BigDecimal:b6ed67bc,‘0.195E4’,4(12)>]

@comptes2=Diario.find_by_sql(“SELECT cuenta, sum(debe) sumdebe from diario where cuenta = ‘430017’ group by cuenta”)
=> [#<Diario cuenta: “430017”>]

No veo que aparezca sumdebe en el retorno de la segunda consulta.Yo creo
que esta mapeando con el modelo.

Ahun que no aparezca el nombre en el retorno no quiere decir que no
puedas acceder al resultado. Puedes evaluar el valor de
@comptes2.first.sumdebe o @comptes2.first[‘sumdebe’] para ver si tiene
valor, pero diria que mejor mires activerecord como hacer esta misma
consulta si utilizar un find_by_sql…

B) Como es posible saber el nombre de las columnas que han retornado un
SQL?

@comptes2.count

Estoy probando de hacer una unica view que pueda pintar los resultados
de diferentes consultas SQL. Para ello, puedo montar dinamicamente el
string SQL (en funcion de los datos que el usuario necesite) y
ejecutarlo, pero necesitaria saber que columnas me devuelven. A priori,
no se como se llaman las columnas, por tanto no puedo utilizar el metodo
respond_to?.
Hay algun array que me indique los atributos de las columnas de una
query?

Utiliza los hacks que no da activerecord en vez de find_by_sql pelado


#4

Hola Emili, que ilusion de ver tus respuestas!!!. Ha sido una gran
alegria y sorpresa!!!

En cuanto al tema que nos ocupa:

A) He ejecutado las siguientes instrucciones desde la consola y el
resultado es el siguiente:

@comptes2=Diario.find_by_sql(“SELECT cuenta, sum(debe) debe from diario where cuenta = ‘430017’ group by cuenta”)
=> [#<Diario cuenta: “430017”, debe:
#BigDecimal:b6ed67bc,‘0.195E4’,4(12)>]

@comptes2=Diario.find_by_sql(“SELECT cuenta, sum(debe) sumdebe from diario where cuenta = ‘430017’ group by cuenta”)
=> [#<Diario cuenta: “430017”>]

No veo que aparezca sumdebe en el retorno de la segunda consulta.Yo creo
que esta mapeando con el modelo.

B) Como es posible saber el nombre de las columnas que han retornado un
SQL?
Estoy probando de hacer una unica view que pueda pintar los resultados
de diferentes consultas SQL. Para ello, puedo montar dinamicamente el
string SQL (en funcion de los datos que el usuario necesite) y
ejecutarlo, pero necesitaria saber que columnas me devuelven. A priori,
no se como se llaman las columnas, por tanto no puedo utilizar el metodo
respond_to?.
Hay algun array que me indique los atributos de las columnas de una
query?

Hola Rafa :wink:

A raiz de este problema, se me han planteado 2 preguntas:
a) Como se puede hacer SQL libres sin pasar por el mapping del modelo?

Cundo haces un find_by_sql se ejecuta la sentencia SQL directamente, con
lo
cual al mapping del modelo no deberia afectarte

b) Como es posible saber el nombre de las columnas que han retornado un
SQL?

El resultado de un find es un array de objetos, si lo recorres puedes
hacer
un respond_to? para ver si existe ese atributo

@cuentas.each do |cuenta|
if cuenta.respond_to? :sumdebe

end
end


#5

Creo que debe ser algo asi:

Diario.sum(‘debe’, :group => ‘cuenta’)

El 26/03/2009, a las 05:29 a.m., Rafa C.
escribió:

Tengo definida una tabla son la siguiente estructura:


#6

2009/3/26 Rafa C. removed_email_address@domain.invalid

where cuenta = ‘430017’ group by cuenta")
=> [#<Diario cuenta: “430017”, debe:
#BigDecimal:b6ed67bc,‘0.195E4’,4(12)>]

@comptes2=Diario.find_by_sql(“SELECT cuenta, sum(debe) sumdebe from
diario where cuenta = ‘430017’ group by cuenta”)
=> [#<Diario cuenta: “430017”>]

No veo que aparezca sumdebe en el retorno de la segunda consulta.Yo creo
que esta mapeando con el modelo.

Segun la documentación [1] el metodo find_by_sql hace

Executes a custom SQL query against your database and returns all the
results. The results will be returned as an array withcolumns requested
encapsulated as attributes of the model you call this method from. If
you
call Product.find_by_sql then the results will be returned in a Product
object with the attributes you specified in the SQL query.

Osea que si mapea el resultado sobre los atributos del Modelo. Tenias
razon.
Puedes probar a crear un accessor a ver si mapea el resultado en él.

class Cuenta < ActiveRecord::Base
attr_accessor :sumdebe
end

respond_to?.
Hay algun array que me indique los atributos de las columnas de una
query?

Sobre un objeto puedes hacer

@cuentas.attribute_names

y te devuelve un array con todos los atributos del modelo.

[1] http://api.rubyonrails.org/classes/ActiveRecord/Base.html#M002212