Documentos de Académico
Documentos de Profesional
Documentos de Cultura
COLABORACIONES
Criterios alternativos de
selección de filas de SQL
revisitados, revisitados
Después de escribir el artículo Guru: Alternate SQL select;
Row-Selection Criteria Revisited, me tomé en serio el uso when SelectByClass = '1';
de SQL dinámico en mis programas RPG en lugar de exec sql open Inp using :iClass;
habilitar y deshabilitar expresiones lógicas en la cláusula when SelectByZip = '1';
WHERE. Estoy reviviendo los días en que OPNQRYF era exec sql open Inp using :iFromZip,
mi mejor amigo, tratando de hacer que los apóstrofos :iThruZip;
vayan bien con la concatenación de cadenas. other;
exec sql open Inp;
En general, estoy contento con el cambio. Cuando he endsl;
convertido la versión cargada de conmutadores a SQL
dinámico, he visto una mejora notable del rendimiento en Tuve que usar múltiples instrucciones abiertas para
algunos casos, y al menos un ligero rendimiento en la acomodar diferentes de marcadores de parámetros, los
mayoría de los casos. En algunos casos, no hay ninguna signos de interrogación que se usan en SQL dinámico
diferencia, aunque Visual Explain muestra menos pasos como marcadores de posición para los valores de los
para recuperar los datos. parámetros. Cuantas más opciones le des al usuario, más
declaraciones abiertas terminarás teniendo que usar.
Una cosa es una molestia especialmente aburrida, a
saber, tener que codificar múltiples instrucciones de Sin embargo, IBM ideó cuidadosamente una forma de
cursor OPEN para acomodar múltiples listas de usar una instrucción abierta independientemente del
parámetros. Si miras el artículo antes mencionado, verás número de marcadores de parámetros en una cadena de
esto en el último fragmento de código: consulta. Es fácil y me gusta mucho.
Una sola instrucción OPEN toma el lugar de las tres En este ejemplo, he definido dos variables indicadoras:
declaraciones OPEN que se muestran arriba. una para la clase y otra para los dos campos de código
postal.
exec sql open Inp using subset
:iClass :Indic_Class, Cada variable indicadora debe establecerse en uno de
:iFromZip :Indic_Zip, dos valores. Cero significa que la variable debe ser
:iThruZip :Indic_Zip; utilizada y (-7) que la variable debe ser ignorada. Definí
dos constantes numéricas en un intento de hacer que el
Observe la palabra SUBSET después de USING. Esto código sea más comprensible.
le indica a SQL que puede o no usar todos los parámetros.
De hecho, puede no usar ninguno de ellos en absoluto. En La otra cosa que debe hacer es asegurarse de que las
este caso, tengo tres marcadores de parámetros potenciales variables indicadoras sean consistentes con la cadena de
en la consulta para representar la clase, desde el código consulta.
postal y hasta el código postal.
Stmt = 'select cusnbr, cusname,
Después de cada parámetro, coloqué una variable cuszip, cusclass from customers';
indicadora para decirle a SQL si ese parámetro se está
utilizando o no. Una variable indicadora es un valor select;
entero de cinco dígitos. when iClass <> *blanks;
Stmt += ' where cusclass = ?';
dcl-s Indic_Zip int(5) Indic_Class = Assigned;
inz(Unassigned); when iFromZip <> *blanks;
dcl-s Indic_Class int(5) Stmt += ' where cuszip between ?
inz(Unassigned); and ?';
Indic_Zip = Assigned;
dcl-c Assigned const(*zero); endsl;
dcl-c Unassigned const(-7);
En este ejemplo, permito que el usuario recupere todas
las filas, solo las filas de una determinada clase o todas las endif;
filas dentro de un rango de códigos postales, if iThruZip <> *blanks
and iThruZip <> iFromZip;
Por supuesto, no hay ninguna razón por la que no Where += (And + ' (cuszip
pueda permitir que el usuario seleccione tanto la clase between ? and ?)');
como el rango de códigos postales. Indic_Thru_Zip = Assigned;
else;
dcl-s Indic_From_Zip int(5) Where += (And + ' (cuszip =
inz(Unassigned); ?)');
dcl-s Indic_Thru_Zip int(5) endif;
inz(Unassigned); endif;
dcl-s Indic_Class int(5)
inz(Unassigned); if Where <> *blanks;
Stmt += ' Where ' + Where;
dcl-c Assigned const(*zero); endif;
dcl-c Unassigned const(-7);
Si lo que necesita es dividir una cadena CSV, puede que estamos hablando, se puede usar en cualquier lugar
hacerlo con %SPLIT utilizando el segundo parámetro donde se pueda usar una variable del mismo tipo.
opcional que puede contener uno o más caracteres Entonces, por ejemplo, podría simplemente usar %SPLIT
separadores. De esta manera: como argumento para el código operacional FOR-EACH
en lugar de tener que definir una matriz dentro del
words = %Split( csvString: ',' ); // programa.
Just split at commas f
words = %Split( textString: '.,!? ' or-each word in %Split( textString
); // Split on any major punctuation );
// Process the word ...
Una advertencia aquí. %SPLIT omite los separadores EndFor;
consecutivos. La mayoría de las veces eso es algo bueno,
pero puede presentar un problema en algunas %MINARR Y %MAXARR
circunstancias. Por ejemplo, si estuviera procesando un Cuando %MIN y %MAX se introdujeron por primera
archivo CSV que contiene la cadena ABC,,XYZ usando vez, me alegré de verlos, pero pensé en ese momento que
CPYFRMIMPF, resultaría en tres campos. "ABC", en también sería bueno tener una variante que funcionara en
blanco, y "XYZ". Sin embargo, %SPLIT solo produciría matrices en lugar de una lista de valores. El problema era
dos elementos de matriz porque se omitiría la segunda que en su encarnación original estos BIFs devolvían el
coma. Por lo tanto, en estas circunstancias se puede valor real y cuando se trataba de una matriz uno realmente
requerir algún procesamiento previo de la entrada. querría el índice del valor. Si no está familiarizado con
estos BIF, puede encontrar los conceptos básicos
El segundo ejemplo muestra cómo podría dividir una documentación de IBM.
oración de tal manera que se ignoren la mayoría de los
signos de puntuación. Observe que incluí un espacio en %MINARR y %MAXARR llenan ese vacío.
blanco al final de la cadena para que los espacios contaran %MINARR devuelve el índice del valor más bajo de la
como separador. Si también quisiera ignorar las comillas, matriz y %MAXARR devuelve el índice del más alto.
etc., simplemente las agregaría a la lista de separadores. Estos BIFs se pueden aplicar a una matriz convencional o
a una matriz DS.
No olvide que, debido a que se trata de un BIF de l0
Esta última capacidad es particularmente útil.
Hoy en día hacemos lo mismo con las especificaciones el caso. En su lugar, tenemos que usar el método indirecto
de definición. para declarar dos constantes con nombre. Descubrí esto
de la manera difícil, a pesar de que este comportamiento
dcl-s Cust_Account_Save like(Cust_
está documentado en la referencia de RPG. Evidentemente
Account);
tengo cosas más importantes que hacer que leer manuales.
O al menos deberíamos. He visto mucho código
donde el programador podría haber usado la palabra clave Estas funciones también son útiles al cambiar el tipo
LIKE y no lo hizo, y no estoy hablando de código de datos. Por ejemplo, supongamos que quiero una
antiguo. variable varchar que contenga la misma cantidad de datos
que un campo de caracteres de longitud fija. No puedo
La palabra clave LIKE tiene un segundo argumento usar la palabra clave LIKE, pero puedo hacer esto:
que aumenta o disminuye el tamaño definido de una
variable. Por ejemplo: dcl-s Address char(20);
dcl-s AddrMod
dcl-s Limit packed (7: 2);
varchar(%size(Address));
dcl-s NewLimit like(Limit: +2);
NewLimit se define como de nueve dígitos de largo, Algunos compiladores son más generosos que el
dos de los cuales son posiciones decimales. compilador RPG cuando se trata del uso de constantes.
Supongamos que necesito que una variable sea el doble
IBM también nos proporciona tres funciones de larga que un campo de base de datos. Tal vez voy a
integradas que recuperan información sobre las almacenar la representación hexadecimal del campo en la
definiciones de datos: %SIZE, %LEN y %DECPOS. variable. Tal vez voy a reemplazar cada apóstrofo con dos
Estas maravillosas funciones abren aún más posibilidades apóstrofos. Algunos compiladores permitirían algo como
para que el compilador utilice el encarpetado constante. esto:
Al igual que la palabra clave LIKE, están infrautilizados
y no se aprecian. dcl-s Dirección char(20);
dcl-s AddrMod char(%len(Address)* 2);
Supongamos que necesito recuperar un número
decimal de una cadena de caracteres. La función %DEC No así el compilador RPG. En cambio, tienes que
lleva a cabo dicha tarea fácilmente, pero tiene que saber encontrar otra manera, como este método, que considero
cómo definir el valor resultante. Podría hacer esto: un truco.
dcl-s Limit packed (7: 2);
Limit = %dec (TextValue: 7: 2); dcl-s Address char(20);
dcl-ds AddrMod;
Pero este es mejor: *n like(Address);
dcl-s Limit packed (7: 2); *n like(Address);
end-ds AddrMod;
dcl-c Length const( %Len (Limit) )
dcl-c DecPos const( %DecPos (Limit) ); Cuanto más podamos usar la palabra clave LIKE y las
funciones integradas de definición de datos, más
Limit = %dec (TextValue: Length: DecPos); posibilidades tiene el compilador de usar el encarpetado
constante. Pero, ¿por qué deberíamos preocuparnos por
Si la definición de LIMIT cambia alguna vez, este ello? ¿Porque necesitamos código objeto optimizado? Esa
código toma el cambio con calma. es una buena razón, pero aquí hay una aún mejor: porque
el encarpetado constante hace que los programas sean
Es una peculiaridad, a mi modo de ver, que no menos propensos a romperse cuando los modificamos.
podamos colocar las llamadas a las funciones %LEN y Ud. y yo tenemos cosas más importantes que hacer que
%DECPOS directamente en la función %DEC, pero tal es buscar errores.