LINQ ORDENAR E AGRUPAR PELO MAIOR
olá amigos,
tenho uma lista, com as ultimas vendas, por produto x Cliente.
preciso filtrar a ultima data ( ultima venda) de um produto e cliente , segue a imagem da lista.
obs, tentei fazer esse filtro por SQL direto no mysql, porem demorou muito e chegou a derrubar o servidor.
tenho uma lista, com as ultimas vendas, por produto x Cliente.
preciso filtrar a ultima data ( ultima venda) de um produto e cliente , segue a imagem da lista.
obs, tentei fazer esse filtro por SQL direto no mysql, porem demorou muito e chegou a derrubar o servidor.
Voce está usando uma ferramenta que faz conversões entre Lambda, LINQ e SQL.
Se souber fazer o que quer no SQL, basta fazer a conversão.
Se souber fazer o que quer no SQL, basta fazer a conversão.
KERPLUNK, quando postei aqui, é porque já tinha esgotado todas a minhas tentativas, dai limpei os testes e deixei só a tabela.
o filtro .where(funcion(F) ... buscando pelo IDCLI e IDPRO eu consegui.
mas pegar a maior data ainda não deu certo.
ou nem fazer o filtro de IDCLI e IDPRO, apenas agrupar pelo IDCLI e IDPRO e exibir a ultima data.
por isso peço ajuda.
o filtro .where(funcion(F) ... buscando pelo IDCLI e IDPRO eu consegui.
mas pegar a maior data ainda não deu certo.
ou nem fazer o filtro de IDCLI e IDPRO, apenas agrupar pelo IDCLI e IDPRO e exibir a ultima data.
por isso peço ajuda.
Segue um exemplo. Neste exemplo eu mostro tanto usando lambda quanto linq to sql. Ambos deveriam dar o mesmo resultado.
No caso estou pegando a última venda realizada de um produto por determinado cliente. (Agrupando por cliente e produto e pegando o max da data)
Sobre derrubar o servidor:
Sempre é bom verificar a consulta que está indo pro banco de dados. Dependendo do mapeamento pode ter uma conversão implÃÂcita que pode acabar com sua performance por não usar o índice;
Verifique o plano de execução e veja se está realizando as operações desejadas, assim como as unidades de custo de processamento e leitura de disco.
Crie índices, se necessário;
Crie partições, se necessário;
Abraços!
No caso estou pegando a última venda realizada de um produto por determinado cliente. (Agrupando por cliente e produto e pegando o max da data)
using System;
using System.Collections.Generic;
using System.Linq;
namespace LinqExemploMaxcim
{
class Venda
{
public int IdCliente { get; set; }
public int IdProduto { get; set; }
public DateTime DataVenda { get; set; }
}
static class FabricaVenda
{
internal static IEnumerable<Venda> CriaColecao()
{
return new List<Venda>()
{
new Venda() { IdCliente = 1, IdProduto = 1, DataVenda = new DateTime(2022, 04, 10) },
new Venda() { IdCliente = 1, IdProduto = 1, DataVenda = new DateTime(2022, 04, 03) },
new Venda() { IdCliente = 1, IdProduto = 1, DataVenda = new DateTime(2022, 04, 06) },
new Venda() { IdCliente = 1, IdProduto = 2, DataVenda = new DateTime(2022, 04, 09) },
new Venda() { IdCliente = 1, IdProduto = 3, DataVenda = new DateTime(2022, 04, 15) },
new Venda() { IdCliente = 2, IdProduto = 3, DataVenda = new DateTime(2022, 04, 20) },
new Venda() { IdCliente = 2, IdProduto = 2, DataVenda = new DateTime(2022, 04, 11) },
new Venda() { IdCliente = 2, IdProduto = 2, DataVenda = new DateTime(2022, 04, 17) },
new Venda() { IdCliente = 2, IdProduto = 2, DataVenda = new DateTime(2022, 04, 10) },
};
}
}
class Program
{
static void Main(string[] args)
{
IEnumerable<Venda> vendas = FabricaVenda.CriaColecao();
//VOCÊPODE USAR VIA LAMBDA
IEnumerable<Venda> ultimasVendasPorClienteProdutoViaLambda = vendas
.GroupBy(venda => new { venda.IdCliente, venda.IdProduto })
.Select(venda => new Venda()
{
IdCliente = venda.Key.IdCliente,
IdProduto = venda.Key.IdProduto,
DataVenda = venda.Max(v => v.DataVenda)
});
//MAS O LINQ TO SQL DEVERIA FUNCIONAR TAMBÉM
IEnumerable<Venda> ultimasVendasPorClienteProdutoViaSql = from venda in vendas
group venda by new { venda.IdCliente, venda.IdProduto } into grupo
select new Venda()
{
IdCliente = grupo.Key.IdCliente,
IdProduto = grupo.Key.IdProduto,
DataVenda = grupo.Max(v => v.DataVenda)
};
}
}
}
Sobre derrubar o servidor:
Sempre é bom verificar a consulta que está indo pro banco de dados. Dependendo do mapeamento pode ter uma conversão implÃÂcita que pode acabar com sua performance por não usar o índice;
Verifique o plano de execução e veja se está realizando as operações desejadas, assim como as unidades de custo de processamento e leitura de disco.
Crie índices, se necessário;
Crie partições, se necessário;
Abraços!
DS2t, excelente sua dica, já apliquei aqui.
e isso me empolgou a reduzir o processo, a uma única consulta , ( antes fazia duas, uma com todos os dados , e outra agrupada com ultima data. e filtrando pela maior data.)
porem to com um erro no filtro dentro do grupo. segue imagem.
e isso me empolgou a reduzir o processo, a uma única consulta , ( antes fazia duas, uma com todos os dados , e outra agrupada com ultima data. e filtrando pela maior data.)
porem to com um erro no filtro dentro do grupo. segue imagem.
consegui executar, mas.. não buscar a informação de ultimo pedido e nem o valor.
e demorou quase 20 minutos para rodar. ( a consulta VIEW retorna 1800 linhas)
e demorou quase 20 minutos para rodar. ( a consulta VIEW retorna 1800 linhas)
Não tinha visto que era VB.NET, foi mal ter colocado em C#. Fiz um exemplo em VB, mas te falar que a sintaxe do LINQ no VB é doÃÂda.
Repare que estou usando um IQueryable, ao invés de uma List ou IEnumerable. IQueryable representa uma consulta que ainda não foi processada. Apenas a partir do momento que eu faço o ToList no final, que vai no banco de dados. Dava até para fazer em uma só, mas acho que ficaria muito confuso, até pela sintaxe do VB.NET.
Agora, o que essa consulta vai renderizar, vai depender do seu provedor de conexão com o banco e a versão do EF.
Mas essa seria uma ideia.
Ah, eu também criaria um índice no campo DataVenda, vai ajudar bastante.
Até
Module Program
Public Class Venda
Public Property IdCliente As Integer
Public Property IdProduto As Integer
Public Property DataVenda As DateTime
Public Property CodigoPedido As String
Public Property Valor As Decimal
End Class
Class FabricaVenda
Friend Shared Function CriaColecao() As IEnumerable(Of Venda)
Return New List(Of Venda) From
{
New Venda() With {.IdCliente = 1, .IdProduto = 1, .DataVenda = New DateTime(2022, 4, 1), .CodigoPedido = "A11", .Valor = 22},
New Venda() With {.IdCliente = 1, .IdProduto = 1, .DataVenda = New DateTime(2022, 4, 2), .CodigoPedido = "A12", .Valor = 12},
New Venda() With {.IdCliente = 1, .IdProduto = 1, .DataVenda = New DateTime(2022, 4, 3), .CodigoPedido = "A13", .Valor = 62},
New Venda() With {.IdCliente = 1, .IdProduto = 2, .DataVenda = New DateTime(2022, 4, 4), .CodigoPedido = "A14", .Valor = 21},
New Venda() With {.IdCliente = 1, .IdProduto = 3, .DataVenda = New DateTime(2022, 4, 5), .CodigoPedido = "A15", .Valor = 23},
New Venda() With {.IdCliente = 1, .IdProduto = 3, .DataVenda = New DateTime(2022, 4, 6), .CodigoPedido = "A16", .Valor = 25},
New Venda() With {.IdCliente = 2, .IdProduto = 1, .DataVenda = New DateTime(2022, 4, 7), .CodigoPedido = "A17", .Valor = 43},
New Venda() With {.IdCliente = 2, .IdProduto = 1, .DataVenda = New DateTime(2022, 4, 8), .CodigoPedido = "A18", .Valor = 31},
New Venda() With {.IdCliente = 2, .IdProduto = 2, .DataVenda = New DateTime(2022, 4, 9), .CodigoPedido = "A19", .Valor = 65},
New Venda() With {.IdCliente = 2, .IdProduto = 2, .DataVenda = New DateTime(2022, 4, 8), .CodigoPedido = "B11", .Valor = 41}}
End Function
End Class
Sub Main(args As String())
Dim vendas As IQueryable(Of Venda) = FabricaVenda.CriaColecao().AsQueryable
Dim queryableUltimasVendas As IQueryable(Of Venda) = vendas.
GroupBy(Function(venda) New With {Key venda.IdCliente, Key venda.IdProduto}).
Select(Function(venda) New Venda() With {
.IdCliente = venda.Key.IdCliente,
.IdProduto = venda.Key.IdProduto,
.DataVenda = venda.Max(Function(v) v.DataVenda)})
Dim queryFinal As IQueryable(Of Venda) = From venda In vendas Join
ultimaVenda In queryableUltimasVendas On
New With {Key venda.IdCliente, Key venda.IdProduto, Key venda.DataVenda} Equals
New With {Key ultimaVenda.IdCliente, Key ultimaVenda.IdProduto, Key ultimaVenda.DataVenda}
Select venda
Dim resultado As IEnumerable(Of Venda) = queryFinal.ToList()
End Sub
End Module
Repare que estou usando um IQueryable, ao invés de uma List ou IEnumerable. IQueryable representa uma consulta que ainda não foi processada. Apenas a partir do momento que eu faço o ToList no final, que vai no banco de dados. Dava até para fazer em uma só, mas acho que ficaria muito confuso, até pela sintaxe do VB.NET.
Agora, o que essa consulta vai renderizar, vai depender do seu provedor de conexão com o banco e a versão do EF.
Mas essa seria uma ideia.
Ah, eu também criaria um índice no campo DataVenda, vai ajudar bastante.
Até
Obrigado DS2T, funcionou direitinho. valeu
Tópico encerrado , respostas não são mais permitidas