2011-03-22 23 views
8

Tengo una base de datos Oracle y una tabla con varias columnas que no son nulas, todas con valores predeterminados.Insertar valor predeterminado cuando se inserta nulo

Me gustaría utilizar una declaración de inserción para cualquier dato que quiera insertar, y no me molesto en verificar si los valores insertados son nulos o no.

¿Hay alguna forma de volver al valor predeterminado de la columna cuando se inserta nulo?

tengo este código:

<?php 
if (!empty($values['not_null_column_with_default_value'])) { 
    $insert = " 
     INSERT INTO schema.my_table 
      (pk_column, other_column, not_null_column_with_default_value) 
     VALUES 
      (:pk_column,:other_column,:not_null_column_with_default_value) 
    "; 
} else { 
    $insert = " 
     INSERT INTO schema.my_table 
      (pk_column, other_column) 
     VALUES 
      (:pk_column,:other_column) 
    ";   
} 

Por lo tanto, tengo que omitir la columna en su totalidad, o que tendrá el error "tratando de inserción nula de no columna nula". Por supuesto que tengo varias columnas con nulos, por lo que el código create insert statement es muy ilegible, feo, y simplemente no me gusta de esa manera.

Me gustaría tener un estado de cuenta, algo similar a:

INSERT INTO schema.my_table 
    (pk_column, other_column, not_null_column_with_default_value) 
VALUES 
    (:pk_column,:other_column, NVL(:not_null_column_with_default_value, DEFAULT)); 

Eso, por supuesto, es una consulta hipotética. ¿Conoces alguna forma de lograr ese objetivo con Oracle DBMS?

EDITAR:

Gracias a todos por sus respuestas. Parece que no hay una forma "estándar" de lograr lo que quería, así que acepté la mejor respuesta de la OMI: que debería dejar de ser inteligente y limitarme a omitir los valores nulos a través de declaraciones construidas automáticamente.

No es exactamente lo que me gustaría ver, pero no hay mejor opción.

+0

¿Por qué no entran valor predeterminado de la columna "not_null_column_with_default_value" en lugar de la palabra "DEFAULT" dentro de la "consulta hipotética"? – palindrom

+0

Causa No sé cuál es el valor predeterminado en el momento de insertar. Pero como @Vincent Malgrat sugirió que puedo buscar ese formulario ALL_TAB_COLUMNS – SWilk

Respuesta

11

Para aquellos que leer ahora:

En Oracle 12c hay una nueva característica: DEFAULT ON NULL. Por ejemplo:

CREATE TABLE tab1 (
    col1  NUMBER DEFAULT 5, 
    col2  NUMBER DEFAULT ON NULL 7, 
    description VARCHAR2(30) 
); 

Así que cuando se intenta insertar nulo en col2, esta será automáticamente 7.

2

Como se explica en este AskTom thread, la palabra clave DEFAULT solo funcionará como una expresión independiente en una inserción de columna y no funcionará cuando se combine con funciones o expresiones como NVL.

En otras palabras, esta es una consulta válida:

INSERT INTO schema.my_table 
    (pk_column, other_column, not_null_column_with_default_value) 
VALUES 
    (:pk_column,:other_column, DEFAULT) 

se puede utilizar una consulta dinámica con todas las filas y sea una variable de enlace o la falta constante si la variable es nula. Esto podría ser tan simple como reemplazar la cadena :not_null_column_with_default_value con la cadena DEFAULT en su $insert.

También puede consultar la vista ALL_TAB_COLUMNS y usar nvl(:your_variable, :column_default). El valor predeterminado es la columna DATA_DEFAULT.

+0

Gracias por su sugerencia sobre data_default. Creo que crearé una función 'get_default (: schema,: table,: column)' que utilizará el caché de Oracle, así que no debería ser muy lento. Solo tendré que verificar si el tipo se puede convertir a otros tipos sin problemas. – SWilk

+1

@SWilk: el tipo es el antiguo CLOB. Es solo texto y debe convertirse a una cadena. En su consulta debe * reemplazar * DEFAULT por el valor de esta columna, y no * enlazar * el valor porque el valor predeterminado puede ser una expresión (como 'trunc (sysdate) + 1') –

+0

Buen punto, gracias. – SWilk

1

Creo que la manera más limpia es no mencionarlos en su instrucción INSERT. Puedes comenzar a escribir activadores para completar los valores predeterminados, pero eso es una armadura pesada para lo que pretendes.

¿No es posible reestructurar un poco el código de la aplicación? En PHP, puede construir una instrucción INSERT sin errores, p. Ej. de esta manera:

<?php 
$insert['column_name1'] = 'column_value1'; 
$insert['column_name2'] = 'column_value2'; 
$insert['column_name3'] = ''; 
$insert['column_name4'] = 'column_value4'; 

// remove null values 
foreach ($insert as $key => $value) { 
    if (is_null($value) || $value=="") { 
    unset($insert[$key]); 
    } 
} 

// construct insert statement 
$statement = "insert into table (". implode(array_keys($insert), ',') .") values (:". implode(array_keys($insert), ',:') .")"; 

// call oci_parse 
$stid = oci_parse($conn, $statement); 

// bind parameters 
foreach ($insert as $key => $value) { 
    oci_bind_by_name($stid, ":".$key, $value); 
} 

// execute! 
oci_execute($stid); 
?> 
+0

Y luego "O'Neil" viene como el valor y BUM! Eso realmente funcionaría si se convierte en variables vinculadas (: valores). De todos modos, soy consciente de este patrón, pero estaba buscando cualquier tipo de declaración de Oracle que hiciera el trabajo. Pensé que Oracle podría tener una solución lista para esto. – SWilk

+0

@SWilk tienes razón. Mi ejemplo se puede modificar fácilmente para usar variables de vinculación. De hecho, acabo de hacer. –

0

me gustaría utilizar un inserto comunicado para cualquier dato que quiero inserción, y no se molestan en comprobar si los valores insertados son nulos o no.

Defina su tabla con un valor predeterminado para esa columna. Por ejemplo:

create table myTable 
(
    created_date date default sysdate, 
    ... 
) 
tablespace... 

o modificar una tabla existente:

alter table myTable modify(created_date default sysdate); 

Ahora usted (o cualquiera que utilice myTable) no tienen que preocuparse por los valores por defecto, como debe ser. Solo sé que para este ejemplo, la columna aún puede contener nulos, por lo que alguien podría insertar explícitamente un nulo. Si no se desea, la columna no será nula también.

EDITAR: Asumiendo que lo anterior ya está hecho, puede usar la palabra clave DEFAULT en su declaración de inserción. Yo evitaría desencadenantes para esto.

+0

Las columnas tienen valores predeterminados. La cuestión es que quiero insertar el valor predeterminado cuando la variable enlazada es nula.'insert into tmp_table_tab (aaa, bbb, ccc) values ​​(9, 8, nvl (: my_value, DEFAULT))' da como resultado la expresión faltante ORA-00936. Mientras 'insert into tmp_table_tab (aaa, bbb, ccc) values ​​(9, 8, DEFAULT)' se ejecutaría correctamente, hace algo más de lo que necesito. Me gustaría olvidar el valor de: my_Value y usar una instrucción INSERT para todas las inserciones. – SWilk

+0

bien, ahora entiendo. Desafortunadamente, probablemente no encuentre una solución elocuente para tener una inserción maestra para todas las columnas nulas o no. Si no puede cambiar su inserción stmt en función de qué cols son nulos, entonces un disparador antes de insertar sería la mejor opción. Tenga en cuenta que si se cambia una columna de no nula a nulable, también DEBE cambiar el desencadenante para excluir el uso de valores predeterminados para esa columna. (agrega gastos generales de mantenimiento adicional, así como gastos generales de procesamiento). – tbone

1

La mejor opción para el rendimiento es la primera.

De todos modos, según tengo entendido, no desea repetir los nombres y valores de las columnas de inserción debido a las modificaciones difíciles de realizar. Otra opción que puede utilizar es ejecutar un inserto con returning cláusula seguido de una actualización:

INSERT INTO schema.my_table 
    (pk_column, other_column, not_null_column_with_default_value) 
VALUES 
    (:pk_column,:other_column, :not_null_column_with_default_value) 
RETURNING not_null_column_with_default_value 
INTO :insered_value 

Parece work with PHP.

Después de esto puede verificar null en insered_value variable de enlace. Si es nula puede ejecutar la siguiente actualización:

UPDATE my_table 
    SET not_null_column_with_default_value = DEFAULT 
WHERE pk_column = :pk_column: 
Cuestiones relacionadas