SELECT WHERE field IN (*, x)
Vamos por partes.
Imagina um cenário em que tens uma tabela de parametrização com vários níveis de detalhe que podem ou não estar definidos:
-
BUKRS (empresa)
-
WERKS (plant)
-
LGORT (depósito)
Quando um dos campos está vazio, é um wildcard, ou seja, é válido para todos os valores.
A configuração da tabela é a seguinte:
BUKRS | WERKS | LGORT | VALUE
—|—|—|—
| | | Z1
E1 | W1 | | Z2
E1 | W1 | L1 | Z4
E1 | W2 | | Z3
Portanto, a primeira linha define o valor por defeito e as outras definem valores de outros cenários mais ou menos específicos.
Já vi código com um SELECT para cada possível combinação, que é a coisa mais estúpida possível porque neste casos já são 8 SELECTs e se amanhã alguém adicionar um quarto campo terá de fazer 16 SELECTs.
O mais comum, que na minha opinião é igualmente lamentável, é presumir que os campos se preenchem a partir da esquerda, o que reduz a lógica a um SELECT por cada campo chave da tabela. Algo assim:
SELECT value INTO result
FROM zparams
WHERE BUKRS = i_bukrs
AND WERKS = i_werks
AND LGORT = i_lgort.
IF sy-subrc <> 0.
SELECT value INTO result
FROM zparams
WHERE BUKRS = i_bukrs
AND WERKS = i_werks.
IF sy-subrc <> 0.
SELECT value INTO result
FROM zparams
WHERE BUKRS = i_bukrs.
ENDIF.
ENDIF.
São 3 SELECTs e 2 IFs. É muita coisa.
Até há pouco tempo eu fazia um RANGE para cada campo chave e depois resolvia a coisa com um único SELECT ordenado de forma a que as linhas mais específicas sejam as primeiras:
DATA r_bukrs TYPE RANGE OF bukrs.
DATA r_werks TYPE RANGE OF werks_d.
DATA r_lgort TYPE RANGE OF lgort_d.
IF i_bukrs IS NOT INITIAL.
r_burks = VALUE #( option = 'EQ' sign = 'I' ( low = i_bukrs ) ).
ENDIF.
IF i_werks IS NOT INITIAL.
r_werks = VALUE #( option = 'EQ' sign = 'I' ( low = i_werks ) ).
ENDIF.
IF i_lgort IS NOT INITIAL.
r_lgort = VALUE #( option = 'EQ' sign = 'I' ( low = i_lgort ) ).
ENDIF.
SELECT value INTO result
UP TO 1 ROWS
FROM zparams
WHERE BUKRS IN r_bukrs
AND WERKS IN r_werks
AND LGORT IN r_lgort
ORDER BY bukrs DESCENDING werks DESCENDING lgort DESCENDING.
ENDSELECT.
Ainda é muito código e usa 3 variáveis auxiliares mas ao menos a lógica é mais simples de manter: um SELECT e nenhum IF.
Mas recentemente lembrei-me de que é possível simplificar imenso:
SELECT value INTO result
UP TO 1 ROWS
FROM zparams
WHERE BUKRS IN (space, i_bukrs)
AND WERKS IN (space, i_werks)
AND LGORT IN (space, i_lgort)
ORDER BY bukrs DESCENDING werks DESCENDING lgort DESCENDING.
ENDSELECT.
Olé!! Um SELECT, zero IFs, zero variáveis auxiliares.
Obrigado hello-julie pela foto.
O Abapinho saúda-vos.