Usuário com melhor resposta
Ajuda com Select em várias tabelas [RESOLVIDO]

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
- Editado Fabio M. L. Souza quarta-feira, 26 de setembro de 2012 17:08
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.brSe 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.- Sugerido como Resposta Roberson Ferreira _ quarta-feira, 26 de setembro de 2012 16:45
- Editado Roberson Ferreira _ quarta-feira, 26 de setembro de 2012 16:46
- Marcado como Resposta Fabio M. L. Souza quarta-feira, 26 de setembro de 2012 17:07
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.
- Sugerido como Resposta Alexandre Matayosi quarta-feira, 26 de setembro de 2012 16:00
-
-
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.
-
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.brSe 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.- Sugerido como Resposta Roberson Ferreira _ quarta-feira, 26 de setembro de 2012 16:45
- Editado Roberson Ferreira _ quarta-feira, 26 de setembro de 2012 16:46
- Marcado como Resposta Fabio M. L. Souza quarta-feira, 26 de setembro de 2012 17:07
-