Tuesday, September 23, 2008

Utilizando corretamente o Set User Selection

Após observar em algumas empresas, programas com utilização incorreta do Set User Selection, resolvi redigir este documento. O erro mais grave está na utilização do operador lógico OR no meio da seleção de dados. A utilização errônea do OR pode causar impactos graves; e o pior, os problemas podem ficar camuflados até que uma situação específica ocorra, principalmente se a seleção de dados for complexa. O programa torna-se assim, uma bomba relógio.

Os erros na utilização do Set User Selection ocorrem pela compreensão incorreta do comando. Eu mesmo cometi alguns erros até me deparar com manuais de treinamento da JDEdwards. Creio que a própria estrutura do comando pode induzir ao erro. Às vezes tenho que reler os comandos para me certificar que estão corretos. Uma boa dica é comparar com a seleção de dados visual.

Compreendendo os operadores lógicos no Set User Selection

Os erros de utilização do Set User Selection ocorrem no uso dos operadores lógicos (NONE / AND / OR). Pelo fato de o operador lógico se situar ao final do comando, o desenvolvedor faz a relação deste operador com a linha situada logo abaixo. Isso está incorreto. O operador lógico na verdade relaciona uma determinada linha à linha situada logo acima.

- Operador lógico NONE:

Boa parte dos erros são cometidos na utilização do NONE. A compreensão errônea deste operador pode desencadear uma série de erros em toda a composição da seleção de dados.
O conceito do NONE é muito simples:

1 – O NONE SEMPRE deve ser usado na primeira linha da seleção. Já vi em alguns programas o NONE na última linha. Isso está incorreto. Se compararmos com a seleção de dados visual, o NONE equivalerá ao Where, que sempre vai na primeira linha.

2 – O NONE só não é utilizado na primeira linha quando precisamos relacionar a seleção de dados externa à interna, por AND ou OR.

A definição do NONE segundo o arquivo de help de APIs (“EnterpriseOne 8.93 APIs”) é a seguinte: “‘None’ is used when this is to be the first line of the selection criteria. The other two values (AND/OR) should be used for subsequent lines.”

No entanto, apesar de esteticamente incorreto, se o desenvolvedor utilizar o NONE em outra linha, o programa irá interpretá-lo como AND (ainda bem !). Mas isso poderá dificultar a compreensão do comando e, dependendo da complexidade, poderá induzir o programador a criar uma seleção de dados totalmente incorreta.

Considerações a respeito da primeira linha:

Se eu colocar outro operador lógico (OR ou AND) na primeira linha, isso trará problemas ?
Apesar de não estar totalmente correto, não trará problemas no resultado final.
No entanto, se o “Set Selection Append Flag” for definido como ‘Yes’, o programa relacionará TODA a seleção de dados externa à TODA a seleção de dados interna, baseando-se no operador lógico da primeira linha da seleção interna.

Exemplos:

- Com seleção externa (Set Selection Append Flag = ‘Yes’) e NONE ou AND no início. O NONE terá o efeito de um AND:

Seleção externa:

FDAEXP > 100000

Seleção interna:

Set Selection Append Flag( Yes)
Set User Selection(BC State (F7611B), Equal To , "SP", NONE ou AND)
Set User Selection(BC State - Ship to State (F7611B), Equal To , "SP", AND)
Set User Selection(BC Date - Issue (F7611B), Greater Than or Equal To , "01/01/06", AND)
Set User Selection(BC Date - Issue (F7611B), Less Than or Equal To , "25/01/06", AND)

Cláusula SQL:

SELECT * FROM CRPDTA.F7611B WHERE
( FDAEXP > 100000.000000
AND
( FDADDS = 'SP'
AND FDSHST = 'SP'
AND FDISSU >= 106001
AND FDISSU <= 106025 ) )
ORDER BY FDBNNF ASC,FDBSER ASC,FDN001 ASC,FDDCT ASC,FDUKID ASC


- Com seleção externa (Set Selection Append Flag = ‘Yes’) e OR no início.


Se o OR for colocado na primeira linha, o resultado será a seleção de dados externa OU a interna (levando em consideração que o OR na seleção de dados externa ou interna sempre quebra o SELECT em blocos).


Seleção externa:

FDAEXP > 100000

Seleção interna:

Set Selection Append Flag( Yes )
Set User Selection(BC State (F7611B), Equal To , "SP", OR)
Set User Selection(BC State - Ship to State (F7611B), Equal To , "SP", AND)
Set User Selection(BC Date - Issue (F7611B), Greater Than or Equal To , "01/01/06", AND)
Set User Selection(BC Date - Issue (F7611B), Less Than or Equal To , "25/01/06", AND)

Cláusula SQL:

SELECT * FROM CRPDTA.F7611B WHERE
( FDAEXP > 100000.000000
OR
( FDADDS = 'SP'
AND FDSHST = 'SP'
AND FDISSU >= 106001
AND FDISSU <= 106025 ) )
ORDER BY FDBNNF ASC,FDBSER ASC,FDN001 ASC,FDDCT ASC,FDUKID ASC


- Se o Set Selection Append Flag for definido como ‘No

Neste caso, se o primeiro Set User Selection for NONE, AND ou OR, o efeito será sempre o mesmo. O programa considerará sempre como se fosse NONE.


Seleção externa:

FDAEXP > 100000

Seleção interna:

Set Selection Append Flag( No)
Set User Selection(BC State (F7611B), Equal To , "SP", OR)
Set User Selection(BC State - Ship to State (F7611B), Equal To , "SP", AND)
Set User Selection(BC Date - Issue (F7611B), Greater Than or Equal To , "01/01/06", AND)

Set User Selection(BC Date - Issue (F7611B), Less Than or Equal To , "25/01/06", AND)

Cláusula SQL:

SELECT * FROM CRPDTA.F7611B WHERE
( ( FDADDS = 'SP'
AND FDSHST = 'SP'
AND FDISSU >= 106001
AND FDISSU <= 106025 ) )


- Operador lógico OR:


É na utilização do OR que ocorrem os erros mais sérios. O OR sempre quebra o SELECT em blocos. Se o desenvolvedor relacionar o operador lógico de uma linha com a linha de baixo ao invés de relacioná-lo com a linha de cima, irá cometer um erro fatal. Ao invés de informar o OR na primeira linha do bloco posterior ele irá informar na última linha do bloco anterior, e isso trará um resultado totalmente indesejável.


Veja no seguinte exemplo:

O objetivo desta seleção de dados é o seguinte: Selecionar as Notas Fiscais, cujo estado de saída seja ‘SP’, estado de destino seja diferente de ‘SP’, data de emissão seja maior ou igual a ‘01/01/06’ e menor ou igual a ‘25/01/06’ OU estado de saída seja ‘SP’, estado de destino seja igual a ‘MG’, data de emissão seja maior ou igual a ‘15/01/06’ e menor ou igual a ‘31/01/06’

Para chegar neste resultado, precisamos utilizar os comandos da seguinte maneira:

Set User Selection(BC State (F7611B), Equal To , "SP", NONE)
Set User Selection(BC State - Ship to State (F7611B), Equal To , "SP", AND)
Set User Selection(BC Date - Issue (F7611B), Greater Than or Equal To , "01/01/06", AND)
Set User Selection(BC Date - Issue (F7611B), Less Than or Equal To , "25/01/06", AND)
//
Set User Selection(BC State (F7611B), Equal To , "SP", OR)
Set User Selection(BC State - Ship to State (F7611B), Equal To , "MG", AND)
Set User Selection(BC Date - Issue (F7611B), Greater Than or Equal To , "15/01/06", AND)
Set User Selection(BC Date - Issue (F7611B), Less Than or Equal To , "31/01/06", AND)

Note que o OR vai na primeira linha do segundo bloco da seleção.

Cláusula SQL:

SELECT * FROM CRPDTA.F7611B WHERE
( ( FDADDS = 'SP'
AND FDSHST = 'SP'
AND FDISSU >= 106001
AND FDISSU <= 106025
OR FDADDS = 'SP'
AND FDSHST = 'MG'
AND FDISSU >= 106015
AND FDISSU <= 106031 ) )
ORDER BY FDBNNF ASC,FDBSER ASC,FDN001 ASC,FDDCT ASC,FDUKID ASC

Se fôssemos compor esta seleção de maneira visual, ficaria como abaixo:



- Utilização errônea do operador lógico OR:


Veja abaixo um exemplo de erro mais comumente observado, com a mesma situação que a do exemplo acima:


Set User Selection(BC State (F7611B), Equal To , "SP", AND)
Set User Selection(BC State - Ship to State (F7611B), Equal To , "SP", AND)
Set User Selection(BC Date - Issue (F7611B), Greater Than or Equal To , "01/01/06", AND)
Set User Selection(BC Date - Issue (F7611B), Less Than or Equal To , "25/01/06", OR)
//
Set User Selection(BC State (F7611B), Equal To , "SP", AND)
Set User Selection(BC State - Ship to State (F7611B), Equal To , "MG", AND)
Set User Selection(BC Date - Issue (F7611B), Greater Than or Equal To , "15/01/06", AND)
Set User Selection(BC Date - Issue (F7611B), Less Than or Equal To , "31/01/06", NONE)

Note que o OR foi colocado na última linha do primeiro bloco. O desenvolvedor, para fechar o raciocínio (e completar o erro), informou o NONE na última linha da seleção.

A cláusula SQL ficará da seguinte maneira:

SELECT * FROM CRPDTA.F7611B WHERE
( ( FDADDS = 'SP'
AND FDSHST = 'SP'
AND FDISSU >= 106001
OR FDISSU <= 106025
AND FDADDS = 'SP'
AND FDSHST = 'MG'
AND FDISSU >= 106015
AND FDISSU <= 106031 ) )
ORDER BY FDBNNF ASC,FDBSER ASC,FDN001 ASC,FDDCT ASC,FDUKID ASC

Visualmente ficaria assim:

O resultado da seleção seria: As Notas Fiscais, com estado de saída igual a ‘SP’, estado de destino diferente de ‘SP’, data de emissão maior ou igual a ‘01/01/06’ OU data de emissão menor ou igual a ‘25/01/06’, estado de saída igual a ‘SP’, estado de destino igual a ‘MG’, data de emissão maior ou igual a ‘15/01/06’ e menor ou igual a ‘31/01/06’.

Esse seria um resultado desastroso, se comparado às expectativas que teríamos em relação a esse programa. Agora, imagine, uma seleção complexa quebrada erroneamente pelo OR em uns dez blocos ? Imagine se este programa fosse para atualização de alguma tabela crítica do sistema ? Causaria estragos enormes ! Portanto, temos que tomar o máximo cuidado com isso.

Dica para não errar:

Uma dica que tenho para não cometemos erros na composição do Set User é comparar sempre a seleção de dados com uma que faríamos visualmente. Qualquer seleção interna pode ter uma seleção visual (externa) idêntica. A diferença está somente na posição que o operador lógico se situa na linha da seleção. Na seleção visual, os operadores lógicos estão à esquerda das linhas e, na interna, à direita (na minha opinião, o correto seria na esquerda também). Para vermos se nossa seleção de dados interna está correta basta transferirmos mentalmente os operadores da direita para a esquerda, como se fossem uma coluna.

Exemplo:

Set User Selection(BC State (F7611B), Equal To , "SP", NONE)
Set User Selection(BC State - Ship to State (F7611B), Equal To , "SP", AND)
Set User Selection(BC Date - Issue (F7611B), Greater Than or Equal To , "01/01/06", AND)
Set User Selection(BC Date - Issue (F7611B), Less Than or Equal To , "25/01/06", AND)
//
Set User Selection(BC State (F7611B), Equal To , "SP", OR)
Set User Selection(BC State - Ship to State (F7611B), Equal To , "MG", AND)
Set User Selection(BC Date - Issue (F7611B), Greater Than or Equal To , "15/01/06", AND)
Set User Selection(BC Date - Issue (F7611B), Less Than or Equal To , "31/01/06", AND)

Se transferirmos os operadores lógicos para a esquerda, ficaria o seguinte:

NONE Set User Selection(BC State (F7611B), Equal To , "SP", )
AND Set User Selection(BC State - Ship to State (F7611B), Equal To , "SP", )
AND Set User Selection(BC Date - Issue (F7611B), Greater Than or Equal To , "01/01/06", )
AND Set User Selection(BC Date - Issue (F7611B), Less Than or Equal To , "25/01/06",)
//
OR Set User Selection(BC State (F7611B), Equal To , "SP", )

AND Set User Selection(BC State - Ship to State (F7611B), Equal To , "MG",)
AND Set User Selection(BC Date - Issue (F7611B), Greater Than or Equal To , "15/01/06",)
AND Set User Selection(BC Date - Issue (F7611B), Less Than or Equal To , "31/01/06",)

Agora fica fácil. Comparando com a seleção visual, o NONE seria o Where e as demais linhas seriam idênticas:






Outra dica seria, durante os testes, ativar o jdedebug.log e analisar a cláusula SQL gerada pelo programa.


Bom trabalho a todos !!!

Eduardo Camargo dos Santos

No comments:

Post a Comment

Thanks for your comment!

Oracle is a registered trademark of Oracle Corporation and/or its affiliates.
JDEFusion is not affiliated with Oracle Corporation. Contents of this site are not endorsed nor approved by Oracle.
JDEFusion is part of Oracle official OTN blogs listing for Latin America under category JD Edwards and Fusion Middleware.