Justificação LNNVL

12

LNNVL é uma função integrada do oracle que retorna TRUE para condições avaliadas como FALSE ou UNKNOWN e retorna FALSE para condições avaliadas como TRUE. Minha pergunta é qual seria o benefício de retornar o oposto da condição de verdade, em vez de apenas manipular os valores NULL?

Por exemplo, suponha que você tenha uma tabela Emp com as colunas StartCommission e CurrentCommission que podem conter nulos. O seguinte retorna apenas linhas com nenhum valor nulo:

SELECT * FROM Emp WHERE StartCommission = CurrentCommission;

Se você deseja incluir linhas em que qualquer comissão é nula, você pode fazer algo assim:

SELECT * FROM Emp WHERE StartCommission = CurrentCommission 
OR StartCommission IS NULL OR CurrentCommission IS NULL;

Parece que existiria uma função para reduzir essa sintaxe, mas o uso de LNNVL retorna todos os registros diferentes e todos os registros com valores nulos.

SELECT * FROM Emp WHERE LNNVL(StartCommission = CurrentCommission);

A adição de NOT a isso retorna apenas linhas sem nulos. Parece-me que a funcionalidade desejada para este caso seria manter verdadeiras condições verdadeiras, falsas condições falsas e avaliar condições verdadeiras como verdadeiras. Eu realmente criei um caso de uso baixo aqui? É realmente mais provável querer transformar desconhecido em verdadeiro, verdadeiro em falso e falso em verdadeiro?

create table emp (StartCommission Number(3,2), CurrentCommission Number(3,2));
insert into emp values (null,null);
insert into emp values (null,.1);
insert into emp values (.2,null);
insert into emp values (.3,.4);
Leigh Riffel
fonte
Hoje conheci o LNNVL e estou tentando descobrir ou entender essa parte também "qual seria o benefício de retornar o oposto da verdade". No entanto, a instrução que você usa para exemplificar LNNVL deve usar o operador não igual: SELECT * FROM Emp WHERE LNNVL (StartCommission <> CurrentCommission); para que ele retorne o mesmo resultado que a instrução usando ORs. Em outras palavras, se estamos usando uma condição e também queremos incluir linhas com valor NULL, precisamos passar a negação de nossa condição para LNNVL.
Apenas você
Outro exemplo simples. Somente funcionários que realmente recebem uma comissão inferior a 20%: SELECT * FROM empregados WHERE commission_pct <.2; Para incluir também funcionários que não recebem comissão: SELECT * FROM empregados WHERE LNNVL (commission_pct> = .2);
Only You
@OnlyYou - Você está correto, para fazer o LNNVL funcionar da mesma forma que a condição teria que ser <>. Eu o deixei = more porque se a função retornasse os mesmos resultados com o sinal =, faria mais sentido. Essencialmente, a função está executando duas ações 1. Inclusão nula, 2. Alternância booleana. O primeiro faz sentido, o posterior apenas parece confundir as coisas que exigem o oposto da condição desejada. ie = requer <>, <requer> =, etc.
Leigh Riffel 9/13

Respostas:

6

É uma função estranha com uma história estranha - mas o nvl2 também é estranho. lnnvlé basicamente um is not trueoperador - sem dúvida, pode ser usado da melhor maneira nvl2possível, mas quando você precisa procurar uma função toda vez que a usa para lembrá-lo exatamente do que faz, fica se perguntando se é melhor seguir nvl, coalesce, decodee nullif, juntamente com caseexpressões, que são mais intuitivos

Jack diz que tenta topanswers.xyz
fonte
Não acho o NVL2 estranho, mas depois uso muito e nunca usei o LNNVL.
Leigh Riffel
@ Leigh - Eu acho que você tem que usá-lo apenas o suficiente para que não se torne estranho :) Eu nunca usei nullifaté perceber que pode ser uma grande ajuda para fazer 'divisão por zero' = nulo. Você realmente acha que o nvl2 (a, c, b) é muito melhor do que decodificar (a, null, b, c)?
Jack diz que tente topanswers.xyz
4

Em outras palavras, ainda não usei o LNNVL em meus vários anos de programador de DBA e PL / SQL. Eu usei o NVL2 de vez em quando (e sempre tive que procurar de que lado era verdade e de que lado não era). Nesse ponto, parece melhor, do ponto de vista da legibilidade, acabar usando NVL, DECODE, CASE etc.,

Como alternativa, isso funciona, supondo que se tenha uma boa noção de como o Oracle lida com NULLs e aritmética, mas a essa altura, pode-se também usar sua consulta original para facilitar a leitura (e o plano de execução também pode sofrer mais):

/* Return all rows where StartCommission is the same
 * as Current Commission, or those rows who have a
 * NULL in either (including both)
 */

SELECT *
  FROM Emp
 WHERE StartCommission = CurrentCommission
    OR StartCommission + CurrentCommission IS NULL

-- NULL + NULL, or NULL + Number is always NULL; hence return either
-- those records that are equal, or have a combined total of NULL
-- (either or both fields will be NULL).
Kerri Shotts
fonte
Você quer dizer StartCommission<>CurrentCommission OR StartCommission + CurrentCommission IS NULL?
Jack diz que tente topanswers.xyz
@JackPDouglas - Faz sentido como =.
Leigh Riffel
Variação interessante. Eu concordo com suas conclusões.
Leigh Riffel
@ Leigh - eu vejo, uma alternativa para a função que você deseja, não uma alternativa para lnnvl.
Jack diz que tente topanswers.xyz
@JackPDouglas - eu entendo e acho que é isso que Kerri pretendia.
Leigh Riffel