2010-03-17 9 views
15

Citando manual de MySQL INSERT - mismo ocurre con ACTUALIZACIÓN:Preparación de una declaración/ACTUALIZACIÓN MySQL INSERT con valores por defecto

Use the keyword DEFAULT to set a column explicitly to its default value. This makes it easier to write INSERT statements that assign values to all but a few columns, because it enables you to avoid writing an incomplete VALUES list that does not include a value for each column in the table. Otherwise, you would have to write out the list of column names corresponding to each value in the VALUES list.

Así que en breve si escribo

INSERT INTO table1 (column1,column2) values ('value1',DEFAULT); 

una nueva fila con columna2 establecer como su valor predeterminado, cualquiera que sea, se inserta.

Sin embargo, si me preparo y ejecuta una instrucción en PHP:

$statement = $pdoObject-> 
    prepare("INSERT INTO table1 (column1,column2) values (?,?)"); 
$statement->execute(array('value1','DEFAULT')); 

La nueva fila contendrá 'por defecto' como su valor de texto - si la columna es capaz de almacenar valores de texto.

Ahora me han escrito una capa de abstracción de DOP (lo necesitaba) y para solucionar este problema estoy considerando introducir una

const DEFAULT_VALUE = "randomstring"; 

Así que podría ejecutar comandos como:

$statement->execute(array('value1',mysql::DEFAULT_VALUE)); 

Y luego, en el método que hace que el enlace pase por los valores que se envían para vincular y si algunos son iguales a self::DEFAULT_VALUE, actúe en consecuencia.

Estoy bastante seguro de que hay una mejor manera de hacerlo. ¿Alguien más ha encontrado situaciones similares?

+0

Desde DOP está procesando sus valores como cadenas sean de entrada, parece que puede que tenga que cambiar el codifica un poco, si eso es posible. Puede cambiarlo para que escriba '... execute (array ('\' value1 \ '', 'DEFAULT'))', pero supongo que PDO está procesando estos valores para usted con 'mysql_real_escape_string() ', etc. Esto vencería a esa función. Probablemente tendrá que simplemente insertarlo directamente en el argumento 'prepare()'. – Jonah

+1

¿Por qué no incluir columnas en su instrucción 'INSERT' que está configurando en un valor distinto al predeterminado? –

+1

El problema es con 'UPDATE' y una entrada enviada vacía. Necesito que sea el predeterminado, no por ejemplo '0000-00-00' para campos de fecha cuando' '' 'se establece como el nuevo valor. – raveren

Respuesta

8

La única "solución" Sé que para esto es utilizar Coalesce() y Default(fieldname)

P. ej

$pdo = new PDO("mysql:host=localhost;dbname=test", 'localonly', 'localonly'); 
$pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION); 

$pdo->exec(" 
    CREATE TEMPORARY TABLE foo (
    id int auto_increment, 
    x int NOT NULL DEFAULT 99, 
    y DATETIME NOT NULL DEFAULT '2010-03-17 01:00:00', 
    z varchar(64) NOT NULL DEFAULT 'abc', 
    primary key(id) 
) 
"); 


$stmt = $pdo->prepare(' 
    INSERT INTO 
    foo 
    (x,y,z) 
    VALUES 
    (
     Coalesce(:x, Default(x)), 
     Coalesce(:y, Default(y)), 
     Coalesce(:z, Default(z)) 
    ) 
'); 
$stmt->bindParam(':x', $x); 
$stmt->bindParam(':y', $y); 
$stmt->bindParam(':z', $z); 


$testdata = array(
    array(null, null, null), 
    array(1, null, 'lalala'), 
    array(null, '2009-12-24 18:00:00', null) 
); 
foreach($testdata as $row) { 
    list($x,$y,$z) = $row; 
    $stmt->execute(); 
} 
unset($stmt); 
foreach($pdo->query('SELECT id,x,y,z FROM foo', PDO::FETCH_NUM) as $row) { 
    echo join(', ', $row), "\n"; 
} 

impresiones

1, 99, 2010-03-17 01:00:00, abc 
2, 1, 2010-03-17 01:00:00, lalala 
3, 99, 2009-12-24 18:00:00, abc 
+1

El valor predeterminado (x) puede ser POR DEFECTO, no es necesario mencionar el nombre de columna si desea el valor predeterminado para esta columna en la misma columna. Es errorprone. ACTUALIZAR t SET x = DEFAULT; –

+0

¡Gran pensamiento! ¡No es perfecto, pero supera mi solución! – raveren

+3

@Frank: Tiene que ser Predeterminado (nombre de campo) cuando se usa como argumento para Coalesce(). – VolkerK

0

trate de cambiar esto:

$statement = $pdoObject-> 
    prepare("INSERT INTO table1 (column1,column2) values (?,?)"); 
$statement->execute(array('value1','DEFAULT')); 

A esto:

$statement = $pdoObject-> 
    prepare("INSERT INTO table1 (column1,column2) values (?,DEFAULT)"); 
$statement->execute(array('value1')); 

Me parece que el código original que va a dar a este:

INSERT INTO table1 (column1,column2) values ('value1','DEFAULT') 

Mi código debe darle esto:

INSERT INTO table1 (column1,column2) values ('value1',DEFAULT) 
+0

¿Quién podría querer otros valores pero predeterminado de todos modos. – raveren

1

he intentado responder a la respuesta VolkerK, pero no podría encontrar la forma. :(estoy algo nuevo en todo esto

De todos modos, he creado una función de MySQL para utilizar en conjunción con su idea COALESCE

CREATE FUNCTION NULLDEFAULT(colname VARCHAR(64), tablename VARCHAR(64), dbname VARCHAR(64)) RETURNS longtext DETERMINISTIC READS SQL DATA 
BEGIN 
    DECLARE retval longtext; 
    SELECT 
     COLUMN_DEFAULT INTO retval 
    FROM 
     information_schema.COLUMNS 
    WHERE 
     TABLE_NAME = tablename 
    AND 
     COLUMN_NAME = colname 
    AND 
     TABLE_SCHEMA = dbname; 

    RETURN retval; 
END 

Usted podría utilizar de esta manera:.

$stmt = $pdo->prepare(" 
    INSERT INTO 
    foo 
    (x,y,z) 
    VALUES 
    (
     Coalesce(:x, NULLDEFAULT('x', 'foo', 'database')), 
     Coalesce(:y, NULLDEFAULT('y', 'foo', 'database')), 
     Coalesce(:z, NULLDEFAULT('z', 'foo', 'database')) 
    ) 
"); 

Eso devolverá nulo si la columna no tiene valor predeterminado y no activará el error "La columna no tiene valor predeterminado".

supuesto, usted podría modificarlo para que no requiere que el parámetro de la base

+0

No creo que se mantenga en cuanto a rendimiento. AFAIK mysql no guardará en caché los resultados de las funciones, por lo que llamaría a su consulta para cada fila y cada columna en la consulta de inserción. Es mucho mejor obtener los valores predeterminados a través de PHP de antemano, pero como ya concluí, mi lección aprendida aquí es no contar en absoluto con los valores predeterminados de mysql. Todavía te daré un +1 por el esfuerzo. – raveren

+0

De acuerdo con la documentación, la palabra clave DETERMINISTIC le dice a mysql que la función siempre devuelve los mismos valores con los mismos parámetros, por lo que me haría creer que almacenará en caché el resultado. Pero no lo he probado extensamente, lo estoy usando en una intranet pequeña sin una notable disminución en la velocidad. –

0

Creo que está escribiendo 'por defecto' la cadena, ya que se escapó por la DOP por lo que hay parámetros para bindValue donde puede especificar el tipo de el valor dado para que pueda enviar un nulo sin comillas y será PDO :: PARAM_NULL; y luego se pondrá valores por defecto, pero no estoy seguro de si hay parámetros similares al enlazar con ejecutar

if(is_int($param)){$pdoParam = PDO::PARAM_INT;} 
     elseif(is_bool($param)){$pdoParam = PDO::PARAM_BOOL;} 
     elseif(is_null($param)){ $pdoParam = PDO::PARAM_NULL;} 
     elseif(is_string($param)){$pdoParam = PDO::PARAM_STR;} 
            else{$pdoParam = FALSE;} 
       $this->_query->bindValue($k,$param,$pdoParam); 
+0

¿Qué se supone que debe lograr '$ pdoParam = FALSE;'? El valor predeterminado es 'PARAM_STR'. – DanMan

Cuestiones relacionadas