Usuário com melhor resposta
Ordem de precedência de parâmetros influenciando em resultados de SELECT

Pergunta
-
Pessoal estou com um problema para fazer a extração de informações de uma base de dados.
Como tem muitos anos que não atuo nessa área, estou com muita dificuldade para solucionar a questão e preciso de ajuda.
SELECT chave_fato, cod_filial, cod_tipo_mv, descricao, num_docto, cod_cli_for, nome_cadastro, CONVERT(CHAR, data_v2, 103) AS 'data emissao', REPLACE(valor_total,'.',',') AS 'Valor total', REPLACE(valor_liquido,'.',',') AS 'Valor liquido', desc_divisao, desc_produto_nf, qtde_pri, cod_unidade_pri, qtde_aux, REPLACE(valor_liquido_item,'.',',') AS 'valor liquido item', status_ctb, MONTH(data_v2) AS 'Mês', DAY(data_v2) AS 'Dia' from vwMovtoEntrada --WHERE DATA_V2 BETWEEN '2019-05-01' AND '2019-05-31' AND desc_divisao LIKE '%bov%' AND COD_TIPO_MV = '811' OR COD_TIPO_MV = 'T816' OR COD_TIPO_MV = 'T819' --WHERE cod_tipo_mv IN ('811','T816','T819') AND data_v2 BETWEEN '2019-05-01' AND '2019-05-31' --AND desc_divisao LIKE '%BOV%' --WHERE data_v2 BETWEEN '2019-05-01' AND '2019-05-31' AND desc_divisao LIKE '%bov%' AND cod_tipo_mv IN ('811','T816','T819') --WHERE DATA_V2 BETWEEN '2019-05-01' AND '2019-05-31' AND COD_TIPO_MV = '811' OR COD_TIPO_MV = 'T816' OR COD_TIPO_MV = 'T819' AND desc_divisao LIKE '%bov%' --WHERE DATA_V2 BETWEEN '2019-05-01' AND '2019-05-31' AND desc_divisao LIKE '%bov%' AND COD_TIPO_MV = '811' OR COD_TIPO_MV = 'T816' OR COD_TIPO_MV = 'T819' --WHERE DATA_V2 BETWEEN '2019-05-01' AND '2019-05-31' AND COD_TIPO_MV = '811' OR COD_TIPO_MV = 'T816' OR COD_TIPO_MV = 'T819' AND desc_divisao LIKE '%bov%' --WHERE data_v2 BETWEEN '2019-05-01' AND '2019-05-31' AND desc_divisao LIKE '%bov%' AND cod_tipo_mv IN ('811','T816','T819') ORDER BY data_v2 ASC
Cada um dos códigos condicionais me retorna um resultado diferente.
Qual a ordem correta dos argumentos?
- Editado Flávio Kowalske Mariano terça-feira, 27 de agosto de 2019 12:59 segurança
Respostas
-
Flávio,
Bom, a questão de uma possível ordem correta, poderá variar de acordo com a necessidade, mas sabemos que sempre o operador AND exige que todas as condições sejam satisfatórias "verdadeiras" para o resultado ser apresentado, ao contrário do OR que no mínimo uma das condições e regras aplicadas sendo verdadeira algo será retornado.
O que necessariamente esta query deverá retornar?
Inicialmente eu aplicaria na cláusula query um filtro trazendo somente os COD_TIPO_MV, fazendo uso do operador IN, que por detrás dos panos faz a mesma coisa que OR, mas acaba se tornando mais legível para o entendimento do código, veja esta alteração:
SELECT chave_fato, cod_filial, cod_tipo_mv, descricao, num_docto, cod_cli_for, nome_cadastro, CONVERT(CHAR, data_v2, 103) AS 'data emissao', REPLACE(valor_total,'.',',') AS 'Valor total', REPLACE(valor_liquido,'.',',') AS 'Valor liquido', desc_divisao, desc_produto_nf, qtde_pri, cod_unidade_pri, qtde_aux, REPLACE(valor_liquido_item,'.',',') AS 'valor liquido item', status_ctb, MONTH(data_v2) AS 'Mês', DAY(data_v2) AS 'Dia' from vwMovtoEntrada Where COD_TIPO_MV IN ('811','T816','T819') -- aqui você declara todos os tipos de movimentação -- Go
Se esta query for processada e os dados que você deseja venham a ser apresentados, podemos evoluir mais um pouco informando a faixa de datas que devemos filtras, veja abaixo:
SELECT chave_fato, cod_filial, cod_tipo_mv, descricao, num_docto, cod_cli_for, nome_cadastro, CONVERT(CHAR, data_v2, 103) AS 'data emissao', REPLACE(valor_total,'.',',') AS 'Valor total', REPLACE(valor_liquido,'.',',') AS 'Valor liquido', desc_divisao, desc_produto_nf, qtde_pri, cod_unidade_pri, qtde_aux, REPLACE(valor_liquido_item,'.',',') AS 'valor liquido item', status_ctb, MONTH(data_v2) AS 'Mês', DAY(data_v2) AS 'Dia' from vwMovtoEntrada Where COD_TIPO_MV IN ('811','T816','T816') -- aqui você declara todos os tipos de movimentação -- AND DATA_V2 BETWEEN '2019-05-01' AND '2019-05-31' -- aqui você informa o intevalo de datas -- Go
Processe, verifique se o retorno esta sendo o que você espera, por último aplique a outra condição fazendo o filtro através da busca aproximada com uso no operador LIKE, veja abaixo:
SELECT chave_fato, cod_filial, cod_tipo_mv, descricao, num_docto, cod_cli_for, nome_cadastro, CONVERT(CHAR, data_v2, 103) AS 'data emissao', REPLACE(valor_total,'.',',') AS 'Valor total', REPLACE(valor_liquido,'.',',') AS 'Valor liquido', desc_divisao, desc_produto_nf, qtde_pri, cod_unidade_pri, qtde_aux, REPLACE(valor_liquido_item,'.',',') AS 'valor liquido item', status_ctb, MONTH(data_v2) AS 'Mês', DAY(data_v2) AS 'Dia' from vwMovtoEntrada Where COD_TIPO_MV IN ('811','T816','T816') -- aqui você declara todos os tipos de movimentação -- AND DATA_V2 BETWEEN '2019-05-01' AND '2019-05-31' -- aqui você informa o intevalo de datas -- AND DESC_Divisao Like '%bov%' -- aqui você declara o valor que esta sendo pesquisa com base na expressão bov -- Go
Pois bem, realizei uma análise superficial da sua query, aparentemente você trabalhando com valores fixos e específicos, então não veja a necessidade de criar tantas condições.
Eu particularmente gosto do aplicar no Where inicialmente as condições que vão trazer menos dados e conforme a necessidade vou deixando as condições que possam exigir mais processamento e retorno de dados para o final da minha query, o mesmo eu aplico no Order By, declaro inicialmente as colunas menores e no final as maiores, mas esta é a minha forma de elaborar o meu código, existem muitas discussões sobre isso.
Pense que sempre temos que construir condições que possam ser consideradas pelo processador da query satisfatórias para se obter o dado da forma mais específica possível, um conceito bastante apresentado aqui nos fóruns chamada do SARgable, no qual a forma que montamos a expressão da condição estará totalmente satisfatória para se obter o dado que é passado no parâmetro, sendo que também o valor do dado deverá ajudar para que isso possa acontecer.
Pedro Antonio Galvão Junior [MVP | MCC | MSTC | MIE | Microsoft Evangelist | Microsoft Partner | Engenheiro de Softwares | Especialista em Banco de Dados Relacional e Data Warehouse | Professor Universitário | @JuniorGalvaoMVP | http://pedrogalvaojunior.wordpress.com]
- Editado Junior Galvão - MVPMVP terça-feira, 27 de agosto de 2019 13:53 Correção de erros de português...
- Marcado como Resposta Flávio Kowalske Mariano quarta-feira, 28 de agosto de 2019 21:27
Todas as Respostas
-
-
-
-
Flávio,
Bom, a questão de uma possível ordem correta, poderá variar de acordo com a necessidade, mas sabemos que sempre o operador AND exige que todas as condições sejam satisfatórias "verdadeiras" para o resultado ser apresentado, ao contrário do OR que no mínimo uma das condições e regras aplicadas sendo verdadeira algo será retornado.
O que necessariamente esta query deverá retornar?
Inicialmente eu aplicaria na cláusula query um filtro trazendo somente os COD_TIPO_MV, fazendo uso do operador IN, que por detrás dos panos faz a mesma coisa que OR, mas acaba se tornando mais legível para o entendimento do código, veja esta alteração:
SELECT chave_fato, cod_filial, cod_tipo_mv, descricao, num_docto, cod_cli_for, nome_cadastro, CONVERT(CHAR, data_v2, 103) AS 'data emissao', REPLACE(valor_total,'.',',') AS 'Valor total', REPLACE(valor_liquido,'.',',') AS 'Valor liquido', desc_divisao, desc_produto_nf, qtde_pri, cod_unidade_pri, qtde_aux, REPLACE(valor_liquido_item,'.',',') AS 'valor liquido item', status_ctb, MONTH(data_v2) AS 'Mês', DAY(data_v2) AS 'Dia' from vwMovtoEntrada Where COD_TIPO_MV IN ('811','T816','T819') -- aqui você declara todos os tipos de movimentação -- Go
Se esta query for processada e os dados que você deseja venham a ser apresentados, podemos evoluir mais um pouco informando a faixa de datas que devemos filtras, veja abaixo:
SELECT chave_fato, cod_filial, cod_tipo_mv, descricao, num_docto, cod_cli_for, nome_cadastro, CONVERT(CHAR, data_v2, 103) AS 'data emissao', REPLACE(valor_total,'.',',') AS 'Valor total', REPLACE(valor_liquido,'.',',') AS 'Valor liquido', desc_divisao, desc_produto_nf, qtde_pri, cod_unidade_pri, qtde_aux, REPLACE(valor_liquido_item,'.',',') AS 'valor liquido item', status_ctb, MONTH(data_v2) AS 'Mês', DAY(data_v2) AS 'Dia' from vwMovtoEntrada Where COD_TIPO_MV IN ('811','T816','T816') -- aqui você declara todos os tipos de movimentação -- AND DATA_V2 BETWEEN '2019-05-01' AND '2019-05-31' -- aqui você informa o intevalo de datas -- Go
Processe, verifique se o retorno esta sendo o que você espera, por último aplique a outra condição fazendo o filtro através da busca aproximada com uso no operador LIKE, veja abaixo:
SELECT chave_fato, cod_filial, cod_tipo_mv, descricao, num_docto, cod_cli_for, nome_cadastro, CONVERT(CHAR, data_v2, 103) AS 'data emissao', REPLACE(valor_total,'.',',') AS 'Valor total', REPLACE(valor_liquido,'.',',') AS 'Valor liquido', desc_divisao, desc_produto_nf, qtde_pri, cod_unidade_pri, qtde_aux, REPLACE(valor_liquido_item,'.',',') AS 'valor liquido item', status_ctb, MONTH(data_v2) AS 'Mês', DAY(data_v2) AS 'Dia' from vwMovtoEntrada Where COD_TIPO_MV IN ('811','T816','T816') -- aqui você declara todos os tipos de movimentação -- AND DATA_V2 BETWEEN '2019-05-01' AND '2019-05-31' -- aqui você informa o intevalo de datas -- AND DESC_Divisao Like '%bov%' -- aqui você declara o valor que esta sendo pesquisa com base na expressão bov -- Go
Pois bem, realizei uma análise superficial da sua query, aparentemente você trabalhando com valores fixos e específicos, então não veja a necessidade de criar tantas condições.
Eu particularmente gosto do aplicar no Where inicialmente as condições que vão trazer menos dados e conforme a necessidade vou deixando as condições que possam exigir mais processamento e retorno de dados para o final da minha query, o mesmo eu aplico no Order By, declaro inicialmente as colunas menores e no final as maiores, mas esta é a minha forma de elaborar o meu código, existem muitas discussões sobre isso.
Pense que sempre temos que construir condições que possam ser consideradas pelo processador da query satisfatórias para se obter o dado da forma mais específica possível, um conceito bastante apresentado aqui nos fóruns chamada do SARgable, no qual a forma que montamos a expressão da condição estará totalmente satisfatória para se obter o dado que é passado no parâmetro, sendo que também o valor do dado deverá ajudar para que isso possa acontecer.
Pedro Antonio Galvão Junior [MVP | MCC | MSTC | MIE | Microsoft Evangelist | Microsoft Partner | Engenheiro de Softwares | Especialista em Banco de Dados Relacional e Data Warehouse | Professor Universitário | @JuniorGalvaoMVP | http://pedrogalvaojunior.wordpress.com]
- Editado Junior Galvão - MVPMVP terça-feira, 27 de agosto de 2019 13:53 Correção de erros de português...
- Marcado como Resposta Flávio Kowalske Mariano quarta-feira, 28 de agosto de 2019 21:27
-
Prezado Flavio,
Mas, realmente cada uma das opções da um resultado diferente devido a ordem dos operadores mudarem a precedência das queries.
Combinar condições quando OR tem precedência (Visual Database Tools)
Dê uma olhada no link acima para ver se lhe ajuda.
O uso de parenteses resolve exatamente a definir quem vem 'primeiro' na leitura da querie.
Você quem precisa entender qual a lógica que é necessário aplicar para o seu caso e a partir dai usar os parenteses deixando claro para o Sql Server qual a ordem que você quer que a querie seja lida.
Jefferson Clyton Pereira da Silva - [MCSA | MCP | MCTS | MTA | Analista de Banco de Dados - Sql Server e Oracle ]