none
Sumar columnas RRS feed

  • Pregunta

  • Hola 

    Deseo convertir esta consulta SQL 

    SELECT 
        SUM(MontoInicial)AS MontoInicial, 
        SUM(CASE WHEN TipoMovimiento = 1 THEN Ingreso END) AS Ingreso,
        SUM(CASE WHEN TipoMovimiento = 2 THEN Ingreso END) AS Devolucion,
        SUM(Egreso)AS Egreso    
    FROM MovimientoCajas
    WHERE CAST(Fecha as date) = CAST('20181219' as date) AND PuntoEmisionId = 4
    GO

    A LINQ

    Lo he intentado de la siguiente manera

    var result = from m in context.MovimientoCajas
                        where DbFunctions.TruncateTime(m.Fecha) == DbFunctions.TruncateTime(fecha)
                              && m.PuntoEmisionId == puntoEmision
                        select new MontoCajaExtend()
                        {
                            MontoInical = m.MontoInicial,
                            Ingreso = m.TipoMovimiento == MovimientoCajaType.Ingreso
                                ? m.Ingreso
                                : 0,
                            Devolucion = m.TipoMovimiento == MovimientoCajaType.Devolucion
                                ? m.Ingreso
                                : 0,
                            Egreso = m.Egreso
                        };
                    return result.Sum();

    Donde pongo Sum me da error que deberia de ser Iquereyable y tener una sobrecarga int

    Saludos!

     

    Pedro Ávila
    "El hombre sabio querrá estar siempre con quien sea mejor que él."
    Lima - Perú


    • Editado Pedro Ávila jueves, 20 de diciembre de 2018 15:31
    jueves, 20 de diciembre de 2018 15:30

Respuestas

  • hola

    >>¿Que significa el 1?

    entiendo que estas indicando el ordinal de la columna por la cual agrupa

    How to Group By “Nothing” in SQL

    la verdad no recomiendoque vayas por este camino, es para problemas

    saludos


    Leandro Tuttini

    Blog
    MVP Profile
    Buenos Aires
    Argentina

    • Marcado como respuesta Pedro Ávila jueves, 20 de diciembre de 2018 19:01
    jueves, 20 de diciembre de 2018 18:40
  • hola

    Pero alli no estas devolviendo una lista, es mas el SELECT seguro devuelve siempr eun solo registro, porque sumas todos los campos no defines ningun GROUP BY

    Puedes aplicar el filtro sore los datos y luego solo sumar las propiedades de forma individual

    var result = (from m in context.MovimientoCajas
                  where DbFunctions.TruncateTime(m.Fecha) == DbFunctions.TruncateTime(fecha)
                          && m.PuntoEmisionId == puntoEmision
                  select m).ToList();
    
    var MontoInical = result.Sum(x=> x.MontoInical);
    var Ingreso = result.Where(m=>m.TipoMovimiento == MovimientoCajaType.Ingreso)
                        .Sum(x=> x.Ingreso);
    var Devolucion = result.Where(m=> m.TipoMovimiento == MovimientoCajaType.Devolucion)
                           .Sum(x=>x.Devolucion);
    var Egreso = result.Sum(x=>x.Egreso);

    Igual algo me suena raro al no aplicar filtro por tipo de movimiento para el moto inicial y egreso, pero quiero pensar que estos campos permiten null por lo que se completan segun corresponda


    saludos


    Leandro Tuttini

    Blog
    MVP Profile
    Buenos Aires
    Argentina


    jueves, 20 de diciembre de 2018 16:33

Todas las respuestas

  • Primero, comencemos por el último punto: Donde pone return result.Sum(), esto no puede funcionar porque está intentando sumar los valores que hay en result, pero en result hay objetos complicados, no es una lista de números, y por lo tanto no se pueden sumar. Y no, el hecho de que esos objetos complejos contengan algunos números en su interior no significa que se puedan sumar. Sum() no tiene la "inteligencia" de entrar dentro de los objetos que le entregas, ver si dentro contienen números y sumar cada uno de los números.

    Y lo de que debería ser IQueryable hace referencia al hecho de que no sabe cómo tomar esa expresión LINQ que le has pasado y convertirla en SQL. Esto, por desgracia, orurre con cierta frecuencia: cuando usas linq-to-entities, la forma en la que lo ejecuta es que toma la expresión que has escrito en LINQ con C#, la traduce a SQL, y la manda a ejecutar en el servidor de base de datos. Pero LINQ-to-entities no es lo bastante "listo" como para saber traducir a SQL cualquier cosa que se pueda escribir en C#. Así que hay muchas expresiones en LINQ que funcionarían si fuese LINQ-to-Objects (ejecutado íntegramente en C#) pero que no se pueden usar con LINQ-to-SQL o LINQ-to-Entities.

    Mi recomendación para estos casos en los que tienes un SQL complicado es no intentarlo escribir con LINQ. Incluso aunque al final lo consigas, te queda enrevesadísimo y es difícil de entender y mantener, y encima puede volverse muy inieficiente porque lo traduce en un SQL todavía más enrevesado. Es preferible dejarlo como SQL, bien sea configurándolo en el servidor usando una Vista, o bien si tu EF es lo bastante moderno usando ExecuteSQL.

    jueves, 20 de diciembre de 2018 16:03
  • hola

    Pero alli no estas devolviendo una lista, es mas el SELECT seguro devuelve siempr eun solo registro, porque sumas todos los campos no defines ningun GROUP BY

    Puedes aplicar el filtro sore los datos y luego solo sumar las propiedades de forma individual

    var result = (from m in context.MovimientoCajas
                  where DbFunctions.TruncateTime(m.Fecha) == DbFunctions.TruncateTime(fecha)
                          && m.PuntoEmisionId == puntoEmision
                  select m).ToList();
    
    var MontoInical = result.Sum(x=> x.MontoInical);
    var Ingreso = result.Where(m=>m.TipoMovimiento == MovimientoCajaType.Ingreso)
                        .Sum(x=> x.Ingreso);
    var Devolucion = result.Where(m=> m.TipoMovimiento == MovimientoCajaType.Devolucion)
                           .Sum(x=>x.Devolucion);
    var Egreso = result.Sum(x=>x.Egreso);

    Igual algo me suena raro al no aplicar filtro por tipo de movimiento para el moto inicial y egreso, pero quiero pensar que estos campos permiten null por lo que se completan segun corresponda


    saludos


    Leandro Tuttini

    Blog
    MVP Profile
    Buenos Aires
    Argentina


    jueves, 20 de diciembre de 2018 16:33
  • Hola @Leandro

    Siguiendo tu recomendación de agregarle el GROUP BY, conseguí la siguiente consulta.

    var result = from m in context.MovimientoCajas
                        where DbFunctions.TruncateTime(m.Fecha) == DbFunctions.TruncateTime(fecha)
                              && m.PuntoEmisionId == puntoEmision
                        group m by 1
                        into g
                        select new MontoCajaExtend()
                        {
                            MontoInical = g.Sum(x => x.MontoInicial),
                            Ingreso = g.Sum(x => x.TipoMovimiento == MovimientoCajaType.Ingreso ? x.Ingreso : 0),
                            Devolucion = g.Sum(x => x.TipoMovimiento == MovimientoCajaType.Devolucion ? x.Ingreso : 0),
                            Egreso = g.Sum(x => x.Egreso)
                        };

    Igual algo me suena raro al no aplicar filtro por tipo de movimiento para el moto inicial y egreso, pero quiero pensar que estos campos permiten null por lo que se completan segun corresponda

    MontoInicial es una sola columna que lo uso solo para aperturar la caja, ingreso lo uso para los ingresos de las ventas y devoluciones de dinero y egreso solo para egreso. Es por eso que solo aplico el filtro de movimientos en ingreso, por eso cree una clase MontoCajaExtend con las siguientes propiedades(MontoInicial, Ingreso, Devolucion y Egreso).

    Esos campos mencionados no permiten nulos.

    Siguiendo este enlace Optimizing Sum, Count, Min, Max and Average with LINQ

    Veo que usan en la sección Single optimized query (good) lo siguiente:

    var a = db.Invoices.GroupBy(i => 1)
        .Select(g => new { Count = g.Count(),
                   Total = g.Sum(i => i.Paid),
                   Average = g.Average(i => i.Paid) });

    GroupBy(i => 1) que puede ser lo que uso group m by 1 into g

    ¿Que significa el 1? 

    Efectivamente como me habías comentado en la query que proporciono no agrupa en nada creo yo lo usan para obtener Sum en g, pero la query creada sale extensa lo mejor es trabajar con la solución que me planteas. Siguiendo la consulta que plantie en el Profile

    Saludos!


    Pedro Ávila
    "El hombre sabio querrá estar siempre con quien sea mejor que él."
    Lima - Perú




    • Editado Pedro Ávila jueves, 20 de diciembre de 2018 18:26
    jueves, 20 de diciembre de 2018 17:23
  • Hola @Alberto

    Disculpa me demore en responder es que se fue la energía.

    Gracias por el conocimiento aportado me sirve de mucho me aclaras el panorama, pero estoy trabajando con EF 6 y si soporta ExecuteSQL y Execute Raw SQL Queries in Entity Framework 6

    Es verdad que en SQL es una consulta mas eficiente, pero ya estoy subido en Entity Framework cerrando una aplicación, pero si no descarto lo que me recomiendas para reportes en vez de crear una capa ADO.NET para ese fin.

    Saludos!


    Pedro Ávila
    "El hombre sabio querrá estar siempre con quien sea mejor que él."
    Lima - Perú

    jueves, 20 de diciembre de 2018 18:13
  • hola

    >>¿Que significa el 1?

    entiendo que estas indicando el ordinal de la columna por la cual agrupa

    How to Group By “Nothing” in SQL

    la verdad no recomiendoque vayas por este camino, es para problemas

    saludos


    Leandro Tuttini

    Blog
    MVP Profile
    Buenos Aires
    Argentina

    • Marcado como respuesta Pedro Ávila jueves, 20 de diciembre de 2018 19:01
    jueves, 20 de diciembre de 2018 18:40
  • Hola @Leandro

    Me gusta tu solución.


    Pedro Ávila
    "El hombre sabio querrá estar siempre con quien sea mejor que él."
    Lima - Perú

    jueves, 20 de diciembre de 2018 19:01