Condição Where com CASE WHEN

09/05/2023

0

SQL

Pessoal, bom dia.

Tudo bem?

Preciso da ajuda de você, no SQL abaixo:

SELECT
Cod_ref,
marca,
SUM(Valor_liquido) AS valorvendidoperiodo

FROM (SELECT
s.Chave_fato,
s.Num_docto,
s.Data_v1,
s.Data_movto,
s.cod_vend_comp,
s.cod_funcionario1,
tg.Nome_cadastro,
tg.apelido,
si.Cod_produto,
si.Cod_ref,
gr.Descricao AS marca,
p.Desc_produto_est,
p.Desc_produto_nf,
si.Qtde_und,
si.Valor_unitario,
si.Valor_liquido

FROM TBSAIDAS S
INNER JOIN tbSaidasItem si ON si.Chave_fato = s.Chave_fato
INNER JOIN tbcadastrogeral tg ON s.cod_vend_comp = tg.cod_cadastro
INNER JOIN tbcadastrogeral tg1 ON s.Cod_funcionario = tg1.cod_cadastro
INNER JOIN tbProduto p ON p.Cod_produto = si.Cod_produto
INNER JOIN tbProdutoRef pr ON pr.Cod_produto = si.Cod_produto AND pr.Cod_ref = si.Cod_ref
INNER JOIN tbGradeRef gr ON gr.Cod_ref = si.Cod_ref

WHERE
--s.Cod_filial BETWEEN ''''''''-3'''''''' AND ''''''''-4'''''''' AND
s.DATA_V1 BETWEEN ''''''''2023/04/01'''''''' and ''''''''2023/04/01'''''''' AND
s.STATUS_CTB = ''''''''S'''''''' AND
s.STATUS <> ''''''''C'''''''' AND
s.COD_TIPO_MV = ''''''''800'''''''' AND --Tipo de Movimento
si.Cod_ref BETWEEN ''''''''49'''''''' AND ''''''''49'''''''' --Informar o código de referencia (fornecedor)
) AS tb

GROUP BY
Cod_ref,
marca

Nesse SQL preciso implementar a opção de filtrar pelo cod_vend_comp ou cod_funcionario1, como poderia fazer isso no WHERE? Ou seja, o usuário que irá escolher se quer pelo Vendedor ou Funcionário.

Tentei diversas formas mas não consegui chegar em nada.

Pensei em colocar um CASE WHEN no WHERE, mas não consegui saber como fazer isso.

Podem me ajudar?
Paulo

Paulo

Responder

Posts

09/05/2023

Arthur Heinrich

Existem várias maneiras de implementar isso, mas, a maioria delas é muito ruim do ponto de vista da eficiência.

Em geral, para cada conjunto de filtros, é necessário escrever uma query diferente.

Tem gente que gosta de utilizar "OR":

where
...
  (@cod_vend_comp is null or cod_vend_comp = @cod_vend_com)
...


Tem outros que utilizam função:

where
...
  (cod_vend_comp = coalesce(@cod_vend_com,cod_vend_comp))
...


Ambos são péssimos.

Tenha em mente que o banco precisa encontrar um plano de acessos que minimize o acesso a dados e isso depende da seletividade de cada filtro.

Sempre que um filtro é condicional, abre para o banco duas ou mais possibilidades de filtro, o que multiplica a complexidade. Se o filtro depende de parâmetros, você exige do banco que ache o melhor plano a cada conjunto de parâmetros e o banco não pode se beneficiar do soft parse ou pior, utilizando um plano em memória que era adequado a outro conjunto de filtros.

Se o filtro é seletivo, em geral, utilizar índices é melhor do que um full scan. Porém, o banco geralmente utiliza um único índice por acesso. Criar um índice em cada coluna não ajuda para fazer um filtro composto.

Quando criamos índices compostos de várias colunas, o banco filtra estas colunas na ordem em que aparecem no índice. Se a coluna é filtrada com igualdade (coluna = xxx), o índice pode ser utilizado para filtrar a próxima coluna, melhorando o desempenho. Quando uma das colunas é filtrada com range (coluna >= xxx ou coluna between xxx and yyy), esta geralmente passa a ser a última coluna utilizada do índice para o acesso. Todas as demais são apenas filtradas.

Então, se você tem um filtro com range, onde o início e fim são iguais como em:

si.Cod_ref BETWEEN '49' AND '49'

O ideal é alterar para:

si.Cod_ref = '49'

Se você deseja que o banco faça o melhor serviço possível, colabore com ele. Conheça as particularidades do banco que você está utilizando.

Por exemplo,

Tem gente que utiliza a data de processamento para saber quais registros não foram processados, fazendo (dt_processamento is null). Em alguns bancos, como é o caso do Oracle, os valores NULL não são indexados.

Se você utiliza uma função como (upper(nome) like 'PAULO%'), você invalida o acesso pelo índice na coluna "nome" e alguns bancos, como o SQL Server, não aceitam criar índices de função de forma nativa. Dá para fazer no SQL Server fazendo uma gambiarra, mas requer a alteração do modelo.

Evite fazer joins desnecessários. Por exemplo, porque você fez o join com as tabelas tg1, p e pr, se elas não são utilizadas para filtrar registros, nem utilizadas para retornar informações?

Se você mantém as constraints de foreign keys criadas corretamente, alguns bancos como o Oracle conseguem perceber que o join é desnecessário e eliminam a tabela do plano de acesso. Mas, se o banco não possui esta habilidade, ele pode acessar dados desnecessariamente.
Responder

Utilizamos cookies para fornecer uma melhor experiência para nossos usuários, consulte nossa política de privacidade.

Aceitar