Solucionado (ver solução)
Solucionado
(ver solução)
3
respostas

Melhorar Consulta SQL para lançamentos contábeis

Olá. Trabalho com Contabilidade e estou tendo dificuldade com uma consulta SQL. Tenho uma tabela de lançamentos contábeis e preciso fazer uma consulta que está me dando muita dor de cabeça. A tabela é formada pelos seguintes campos:

CodigoEmpresa CodigoLancamento DataLancamento ContaContabilDebito ContaContabilCredito ValorLancamento Historico

O meu objetivo é ter um relatório que vai me dar o somatório a débito e o somatório à crédito por mês para cada conta contábil da empresa selecionada.

Conta Contábil Competência Total Débito Total Crédito Saldo

Eu não sei a melhor maneira de fazer isso no SQL então estou resolvendo no programa, só que está demorando demais. Em alguns casos a consulta retorna uma lista com centenas de milhares de linhas e está muito ruim! Estou pegando os dados assim:

SELECT * FROM LancamentosContabeis WHERE CodigoEmpresa = XXX AND DataLancamento >= XX/XX/XXXX AND DataLancamento <= XX/XX/XXXX)

Nessa lista eu estou fazendo um Loop somando os valores para cada conta quando ela aparece em Débito e quando ela aparece em Crédito para cada mês.

Existe alguma forma de resolver isso no próprio SQL para que a consulta fique mais eficiente? Eu pensei em fazer sub-consultas mas quando comecei a fazer me perdi e a sintaxe do SQL ficou errada.

Detalhe: Existe a tabela de Contas Contábeis também com:

CodigoConta ClassificacaoConta DescricaoConta

Na tabela de Lançamentos um lançamento nunca vai ter a mesma conta no débito e no crédito, porém a mesma conta pode aparecer na parte de Débito em um lançamento e na parte de Crédito em outros lançamentos.

Por ser uma questão mais específica, não sei se posso tratar aqui, mas fiz os cursos de SQL e não consegui resolver meu problema. Se não puder, me desculpem o transtorno e gostaria de uma sugestão de algum fórum que possa me ajudar.

Desde já agradeço.

3 respostas

Se a tabela de lançamentos tivesse apenas 1 campo de conta (e não dois), e houvesse um outro campo para dizer se a operação foi débito ou crédito, o relatório seria menos difícil de fazer, creio que poderia ser feito numa única consulta.

Do jeito que está, uma solução seria criar tabelas auxiliares e fazer todo o processo no SQL. Fazer novas consultas dentro de um loop vai causar problemas se a tabela for muito extensa.

Segue um exemplo de uma extração referente a setembro

1 - Criar uma tabela auxiliar com os resultados da empresa consolidados por tipo de conta e periodo (tabela relatorio1)

SELECT CodigoEmpresa, year(DataLancamento) as ano, month(DataLancamento) as mes, ContaContabilDebito, ContaContabilCredito,  isnull(sum(ValorLancamento),0) as total
into relatorio1 FROM LancamentosContabeis WHERE CodigoEmpresa = XXX AND DataLancamento between '2018-09-01' AND '2018-09-30' GROUP BY CodigoEmpresa, ContaContabilDebito, ContaContabilCredito, month(DataLancamento), year(DataLancamento) ORDER BY year(DataLancamento), month(DataLancamento)

2 - Criar uma segunda tabela chamada relatorio2, contendo os campos conta_contabil, CodigoEmpresa, ano, mes, debito, credito e saldo

3 - Para cada período/empresa, inserir registros na tabela auxiliar relatorio2. Eu tomei como base a sua tabela de contas

insert into relatorio2 (conta_contabil, CodigoEmpresa, ano, mes)
select CodigoConta, xxxx, 9, 2018 from ContasContabeis 

4 - Atualizar a tabela auxiliar relatorio2, tomando como base a tabela relatorio1


update relatorio2 set debito = R1.total from relatorio2 as R2, relatorio1 as R1 where R1.ano = R2.ano and R1.mes = R2.mes and R1.ContaContabilDebito = R2.conta_contabil AND R1.CodigoEmpresa = R2.CodigoEmpresa

update relatorio2 set credito = R1.total from relatorio2 as R2, relatorio1 as R1 where R1.ano = R2.ano and R1.mes = R2.mes and R1.ContaContabilCredito = R2.conta_contabil AND R1.CodigoEmpresa = R2.CodigoEmpresa

update relatorio2 set saldo = credito - debito

A tabela relatorio2 será o resultado final

Oi Daniel. Muito obrigado pelo retorno.

Realmente se a tabela fosse organizada da maneira que descreveu ficaria bem mais fácil, porém o sistema que possuímos é de terceiros e o acesso ao banco de dados, externo ao sistema, é apenas para consulta.

É possível fazer os passos indicados apenas com acesso de consulta ao banco de dados?

Porque eu acho que não consigo criar a tabela auxiliar sem ter a permissão.

solução!

Talvez seja possível criar tabelas temporárias, elas tem o tempo de vida da sua conexão. Se elas forem criadas dentro de uma procedure, o tempo de vida é o tempo de execução da procedure.

Até onde eu vi, não existe restrição para criar tabelas temporárias

https://jasonstrate.com/2013/05/21/security-questions-what-permissions-are-required-to-create-temporary-tables/

Para criar a tabela temporária, basta usar o "#" no começo do nome. Exemplo:

CREATE TABLE #MyTempTable (SiteName varchar(50), BillingMonth varchar(10), Consumption float)

select * from #MyTempTable 

O primeiro select seria alterado de

SELECT ... into relatorio1 FROM LancamentosContabeis ...

para

SELECT ... into #relatorio1 FROM LancamentosContabeis