2009-06-16 23 views
12

¿Existe un equivalente o alternativa a lo siguiente?Oracle 'printf' equivalente

SELECT mix_type || ' (' || mix_num || ')' as description 
    FROM acid_batch 
WHERE mix_num < 10 

¿Oracle tiene algo así como el formato de estilo printf?

SELECT printf("%s (%s)", mix_type, mix_num) as description, 
    FROM acid_batch 
WHERE mix_num < 10 
+2

La sintaxis de (str_a || '' || str_b) o lo anterior para rodear una cadena con paréntesis parece fea (para el código) y difícil de leer. Parece que debería haber una manera más elegante. – Steven

+0

Otra solución sería escribir un paquete pl/sql que tome argumentos y formatee las cosas de la forma que desee. – EvilTeach

+0

Desafortunadamente PL/SQL no (todavía) admite números variables y tipos de parámetros para una función: la forma más cercana sería implementar FUNCTION printf (t varchar2, v1 varchar2: = null, v2 varchar2: = null, v3 varchar2: = null, v4 varchar2: = null, v5 varchar2: = null) RETURN VARCHAR2 (agregue parámetros varchar2 adicionales si los necesita). Aunque consideraría cambiarle el nombre porque el propósito de printf es enviar el resultado a stdout, mientras que aquí espera que simplemente devuelva la cadena resultante. –

Respuesta

6

No hay funciones incorporadas de Oracle que apliquen una cadena de formateo de esta manera. Aunque sería fácil escribir una función personalizada para este ejemplo específico, escribir una implementación basada en PL/SQL de printf sería un desafío.

Si tiene una necesidad frecuente de esto, quizás podría escribir una función de Oracle que envuelva una llamada de Java para un entorno de manejo de cadenas más rico.

+0

Ahora esta es una respuesta anterior, pero ¿sabe si todavía es así? – flindeberg

1

Puede resolverlo en la selección.

SELECT mix_type || '(' || mix_num || ')' as description, 
FROM acid_batch 
WHERE mix_num < 10 

también debe echar un vistazo a las funciones

to_char

to_date

to_number

, ya que le dan una granularidad más fina sobre cómo quiere las cosas representadas.

3

Sólo otra idea para usted: He encontrado Reemplazar a ser útil para este tipo de cosas, sobre todo cuando la plantilla es compleja:

SELECT REPLACE(REPLACE(
     '%mix_type% (%mix_num%)' /*template*/ 
     ,'%mix_type%', mix_type) 
     ,'%mix_num%' , mix_num) as description, 
FROM acid_batch 
WHERE mix_num < 10 

El único inconveniente es que hay que añadir tantos REPLACE( ' ya que hay variables para reemplazar, pero al menos solo necesita tener una por variable, independientemente de cuántas veces aparezca en la plantilla.

(NOTA: No hay significado particular a la utilización de "%" como delimitador, es sólo una convención personal mío - puede elegir un patrón diferente, por ejemplo <mix_type> o [mix_type])

Para este particular instancia que parece una exageración, pero en algunos casos puede hacer las cosas mucho más fácil, por ejemplo:

template := 'bla bla %a% %b% %a%'; 
output := REPLACE(REPLACE(template 
    ,'%a%', some_complex_expression) 
    ,'%b%', b); 

Compare lo anterior con:

output := 'bla bla ' || some_complex_expression || ' ' || b || ' ' || some_complex_expression; 
+0

No es una mala idea, pero probablemente solo desee hacer esto en una plantilla pequeña con pocas variables. Mi razonamiento para esto es que creo que REPLACE analizaría la plantilla una vez antes de cada llamada, por lo que podría consumir la CPU. – aglassman

+0

Si tenía miles de variables, estuvo de acuerdo. Lo he usado para una docena de variables sin impacto apreciable en el rendimiento. En realidad no se trata de "analizar" como tal; un reemplazo es una manipulación de cadena relativamente simple. –

16

La aproximación estándar más cercana a printf para Oracle que puedo pensar es utl_lms.format_message. Sin embargo, no va a funcionar en las instrucciones SQL, es decir, que esto está bien:

begin 
    dbms_output.put_line(
    utl_lms.format_message('hello %s, the number is %d', 'world', 42) 
); 
end; 
/

pero esto le da un ORA-00902 : tipo de datos no válido de error:

select utl_lms.format_message('hello %s, the number is %d', 'world', 42) 
    from dual 
+0

La documentación dice que esto es para mensajes de error ("* UTL_LMS recupera y formatea mensajes de error en diferentes idiomas. *"). ¿Sabes si hay problemas o restricciones con el uso de cadenas normales? La documentación es bastante escasa. –

+0

esta es su forma de hacerlo ... pero todos los parmaters deben ser CHAR/VARCHAR ... es decir '' select utl_lms.format_message ('hello% s, el número es% s', 'world', TO_CHAR (42)) de dual'' – ShoeLace

2

que he hecho un motor de plantilla simple llamado ora_te (on GitHub) para Oracle SQL/PLSQL. Con la ayuda de su meta se puede lograr de la siguiente manera:

aplicación no efectivas con múltiples parsings de cadena de plantilla:

with acid_batch as (
    select rownum as mix_type, rownum + 2 as mix_num 
    from all_objects 
    where rownum < 10 
) 
-- 
SELECT pk_te.substitute('$1 ($2)', ty_p(mix_type, mix_num)) as description 
FROM acid_batch 
WHERE mix_num < 10; 

Una implementación efectiva con una compilación de tiempo (análisis):

with acid_batch as (
    select rownum as mix_type, rownum + 2 as mix_num 
    from all_objects 
    where rownum < 10 
), 
-- 
o as ( 
    select ty_te.compile_numbered('$1 ($2)') te from dual 
) 
SELECT pk_te.substitute(o.te, ty_p(mix_type, mix_num)) as description 
FROM acid_batch, o 
WHERE mix_num < 10; 

BTW también es compatible con marcadores de posición con nombre.

Cuestiones relacionadas