none
Ajuda com Select em várias tabelas [RESOLVIDO] RRS feed

  • Pergunta

  • Amigos,

    Estou usando SQLServer 2008 Express e tenho que realizar um select para retornar dados sobre o histórico de vendas de produtos para uma rotina de cotação de preços. A ideia é trazer todos os produtos amarrados a um determinado fornecedor e trazer dados de vendas destes produtos. O problema é que preciso trazer todos os produtos amarrados ao fornecedor, inclusive os produtos que não tiveram vendas no período. Vamos aos detalhes:

    Campos Tabela produtos:

    PROCOD, DESCPROD, PRVENDA, PRCUSTO

    Campos tabela de ItensVendas

    ID, TrnDat, PROCOD, Quantidade, ValorUnitario, ValorTotal,

    Campos Tabela de Fornecedores

    CodFornecedor, DescFornecedor, 

    Campos Tabela Produtos_Fornecedores

    PROCOD, CodFornecedor

    A pesquisa do histórico de vendas é feita com base nos últimos 30 dias. Tentei criar algo abaixo, mas só retorna os produtos com vendas e não todos como estou precisando.

    select p.procod, p.prodes, sum(i.itvqtdvda) as giro from produtos p 

                                left join itemvenda i on p.procod = i.procod 
                                left join produtos_fornecedores f on p.procod = f.procod 
                                where f.forcod = '0001'  and  TrnDat Between Cast('2012-01-01 00:00:00'  as Datetime) and  Cast('2012-01-31 00:00:00'  as Datetime)
                                group by procod, prodes, giro


    Obrigado,

    Fabio Souza


    Fabio Souza


    quarta-feira, 26 de setembro de 2012 15:25

Respostas

  • Fabio, você tem diversas opções para fazer o que precisa: pode usar CTE, SubSelect, pode inserir os produtos que tiverem venda numa tabela temporária e depois inserir nesta tabela os itens que não tiveram venda no período informado, etc, etc.

    Outra forma é a que segue mais abaixo. Perceba que faço o filtro de datas diretamente no Left Join com a tabela de itens da venda.

    Já com a tabela Produto_Fornecedor eu faço um Inner Join, pois assumo que só quero os produtos que tenham vínculo com o fornecedor filtrado.

    O erro que você cometeu é comum: as pessoas usam Left Join mas filtram informações da tabela no Where. Com isso você está "transformando" o Left Join num Inner Join. Por isso só estava trazendo os produtos que tinham venda.

    Segue exemplo de uma das possíveis maneiras:

    Declare @TabelaProduto Table (CodProduto int, Descricao VarChar(30))
    Declare @TabelaProdutoFornecedor Table (CodProduto int, CodFornecedor int)
    Declare @TabelaProdutoVendas Table (CodProduto int, DataVenda Date, QuantVendida Float)
    
    Insert Into @TabelaProduto Values (10, 'Mouse'), (20, 'Teclado'), (30, 'Gabinete')
    Insert Into @TabelaProdutoFornecedor Values (10, 100), (20, 200), (30, 300)
    Insert Into @TabelaProdutoVendas Values
    (10, '01/05/2012', 25), (10, '01/08/2012', 40), (20, '01/12/2012', 18),
    (10, '01/25/2012', 12), (20, '02/03/2012', 19), (20, '02/14/2012', 23)
    
    Select
      P.CodProduto,
      P.Descricao,
      TotalVendido = Sum(V.QuantVendida)
    From
      @TabelaProduto P Inner Join @TabelaProdutoFornecedor F on (F.CodProduto = P.CodProduto)
                       Left Join (Select CodProduto, QuantVendida From @TabelaProdutoVendas Where DataVenda Between '20120101' and '20120131') V on (V.CodProduto = P.CodProduto)
    Group by
      P.CodProduto,
      P.Descricao


    Roberson Ferreira - Database Developer
    Acesse: www.robersonferreira.com.br
    Email: contato@robersonferreira.com.br

    Se esta sugestão for útil, por favor, classifique-a como útil.
    Se ela lhe ajudar a resolver o problema, por favor, marque-a como Resposta.


    quarta-feira, 26 de setembro de 2012 16:45

Todas as Respostas

  • Fabio, acredito que o problema é que voce esta utilizando no join a tabela de vendas, tente colocar esta tabela somente na condição e não no join como abaixo:

    select p.procod, p.prodes, sum(i.itvqtdvda) as giro from produtos p 
                                 left join produtos_fornecedores f on p.procod = f.procod 
                                 where f.forcod = '0001'  
    			     and p.procod in (select procod from itemvenda where TrnDat Between Cast('2012-01-01 00:00:00'  as Datetime) and  Cast('2012-01-31 00:00:00'  as Datetime))
                                 group by procod, prodes, giro 


    Alexandre Matayosi Conde Mauricio. Se esta sugestão for útil, por favor, classifique-a como útil. Se ela lhe ajudar a resolver o problema, por favor, marque-a como Resposta.

    quarta-feira, 26 de setembro de 2012 15:37
  • Entendi,

    Mas como fica o campo "sum(i.itvqtdvda) as giro" ? Se ele não esta mais no select e sim no SubSelect, como faço para colocar este campo?

    Obrigado,

    Fabio Souza


    Fabio Souza

    quarta-feira, 26 de setembro de 2012 16:02
  • Fabio não tinha reparado neste campo, o problema é que voce quer trazer todos os produtos de um determinado periodo por fornecedor, o left join funcionaria, mas na condição voce esta filtrando pelo periodo de vendas, certo ? Sendo assim a query irá retornar realmente somente os produtos que tiveram venda e não todos os produtos.

    Acho que voce poderia rodar o seu primeiro select que trará os produtos que tiveram venda e depois um segundo select por produto e fornecedor fazendo um not in ou not exists dos produtos e fornecedores do primeiro select, assim voce teria 2 listas dos produtos e fornecedores que tiveram vendas e os que não tiveram, porem no segundo select não poderia consultar a tabela de vendas ja que não existiriam registros.


    Alexandre Matayosi Conde Mauricio. Se esta sugestão for útil, por favor, classifique-a como útil. Se ela lhe ajudar a resolver o problema, por favor, marque-a como Resposta.

    quarta-feira, 26 de setembro de 2012 16:15
  • Fabio, você tem diversas opções para fazer o que precisa: pode usar CTE, SubSelect, pode inserir os produtos que tiverem venda numa tabela temporária e depois inserir nesta tabela os itens que não tiveram venda no período informado, etc, etc.

    Outra forma é a que segue mais abaixo. Perceba que faço o filtro de datas diretamente no Left Join com a tabela de itens da venda.

    Já com a tabela Produto_Fornecedor eu faço um Inner Join, pois assumo que só quero os produtos que tenham vínculo com o fornecedor filtrado.

    O erro que você cometeu é comum: as pessoas usam Left Join mas filtram informações da tabela no Where. Com isso você está "transformando" o Left Join num Inner Join. Por isso só estava trazendo os produtos que tinham venda.

    Segue exemplo de uma das possíveis maneiras:

    Declare @TabelaProduto Table (CodProduto int, Descricao VarChar(30))
    Declare @TabelaProdutoFornecedor Table (CodProduto int, CodFornecedor int)
    Declare @TabelaProdutoVendas Table (CodProduto int, DataVenda Date, QuantVendida Float)
    
    Insert Into @TabelaProduto Values (10, 'Mouse'), (20, 'Teclado'), (30, 'Gabinete')
    Insert Into @TabelaProdutoFornecedor Values (10, 100), (20, 200), (30, 300)
    Insert Into @TabelaProdutoVendas Values
    (10, '01/05/2012', 25), (10, '01/08/2012', 40), (20, '01/12/2012', 18),
    (10, '01/25/2012', 12), (20, '02/03/2012', 19), (20, '02/14/2012', 23)
    
    Select
      P.CodProduto,
      P.Descricao,
      TotalVendido = Sum(V.QuantVendida)
    From
      @TabelaProduto P Inner Join @TabelaProdutoFornecedor F on (F.CodProduto = P.CodProduto)
                       Left Join (Select CodProduto, QuantVendida From @TabelaProdutoVendas Where DataVenda Between '20120101' and '20120131') V on (V.CodProduto = P.CodProduto)
    Group by
      P.CodProduto,
      P.Descricao


    Roberson Ferreira - Database Developer
    Acesse: www.robersonferreira.com.br
    Email: contato@robersonferreira.com.br

    Se esta sugestão for útil, por favor, classifique-a como útil.
    Se ela lhe ajudar a resolver o problema, por favor, marque-a como Resposta.


    quarta-feira, 26 de setembro de 2012 16:45
  • Roberson Ferreira, funcionou com o Select no Left Join, obrigado. Alexandre obrigado também pela ajuda.


    Fabio Souza

    quarta-feira, 26 de setembro de 2012 17:07