MySQL Insertar en varias tablas? (Normalización de la base de datos?)


Intenté buscar una forma de insertar información en varias tablas en la misma consulta, pero descubrí que es imposible? Así que quiero insertarlo simplemente usando consultas mutliple es decir;

INSERT INTO users (username, password) VALUES('test', 'test')
INSERT INTO profiles (userid, bio, homepage) VALUES('[id of the user here?]','Hello world!', 'http://www.stackoverflow.com')

Pero, ¿cómo puedo dar el id de incremento automático del usuario al id de usuario "manual" para la tabla de perfiles?

 108
Author: NBeydon, 2011-03-03

8 answers

No, no se puede insertar en varias tablas en un comando MySQL. Sin embargo, puede usar transacciones.

BEGIN;
INSERT INTO users (username, password)
  VALUES('test', 'test');
INSERT INTO profiles (userid, bio, homepage) 
  VALUES(LAST_INSERT_ID(),'Hello world!', 'http://www.stackoverflow.com');
COMMIT;

Echa un vistazo a LAST_INSERT_ID() reutilizar los valores de autoincremento.

Editar: dijiste " Después de todo este tiempo tratando de averiguarlo, todavía no funciona. ¿No puedo simplemente poner el ID recién generado en un var var y poner ese var var en todos los comandos de MySQL?"

Permítanme elaborar: hay 3 maneras posibles aquí:

  1. En el código ves arriba. Este lo hace todo en MySQL, y el LAST_INSERT_ID() en el segundo declaración será automáticamente valor de la columna autoincremento que se insertó en la primera instrucción.

    Desafortunadamente, cuando la segunda instrucción en sí inserta filas en una tabla con una columna de incremento automático, LAST_INSERT_ID() se actualizará a la de la tabla 2, y no a la tabla 1. Si todavía necesita el de la tabla 1 después, tendremos que almacenarlo en una variable. Esto nos lleva a los caminos 2 y 3:

  2. Almacenará el LAST_INSERT_ID() en una variable MySQL:

    INSERT ...
    SELECT LAST_INSERT_ID() INTO @mysql_variable_here;
    INSERT INTO table2 (@mysql_variable_here, ...);
    INSERT INTO table3 (@mysql_variable_here, ...);
    
  3. Almacenará el LAST_INSERT_ID() en un variable php (o cualquier lenguaje que puede conectarse a una base de datos, de su elección):

    • INSERT ...
    • Use su lenguaje para recuperar el LAST_INSERT_ID(), ya sea ejecutando esa instrucción literal en MySQL, o usando por ejemplo el mysql_insert_id() de php que lo hace por usted
    • INSERT [use your php variable here]

ADVERTENCIA

Cualquier forma de resolver si elige esto, debe decidir qué debe suceder si la ejecución se interrumpe entre consultas (por ejemplo, su servidor de base de datos se bloquea). Si puedes vivir con "algunos han terminado, otros no", no sigas leyendo.

Sin embargo, si decide "o bien todas las consultas terminan, o ninguna termina - No quiero filas en algunas tablas, pero no hay filas coincidentes en otras, siempre quiero que mis tablas de base de datos sean consistentes", debe envolver todas las sentencias en una transacción. Por eso usé el BEGIN y COMMIT aquí.

Comente de nuevo si necesita más información:)

 189
Author: Konerak,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-09-25 08:10:03

Bastante simple si utiliza procedimientos almacenados:

call insert_user_and_profile('f00','http://www.f00.com');

Guión completo:

drop table if exists users;
create table users
(
user_id int unsigned not null auto_increment primary key,
username varchar(32) unique not null
)
engine=innodb;

drop table if exists user_profile;
create table user_profile
(
profile_id int unsigned not null auto_increment primary key,
user_id int unsigned not null,
homepage varchar(255) not null,
key (user_id)
)
engine=innodb;

drop procedure if exists insert_user_and_profile;

delimiter #

create procedure insert_user_and_profile
(
in p_username varchar(32),
in p_homepage varchar(255)
)
begin
declare v_user_id int unsigned default 0;

insert into users (username) values (p_username);
set v_user_id = last_insert_id(); -- save the newly created user_id

insert into user_profile (user_id, homepage) values (v_user_id, p_homepage);

end#

delimiter ;

call insert_user_and_profile('f00','http://www.f00.com');

select * from users;
select * from user_profile;
 14
Author: Jon Black,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2011-03-03 09:27:30

Prueba esto

$sql= " INSERT INTO users (username, password) VALUES('test', 'test') ";
mysql_query($sql);
$user_id= mysql_insert_id();
if(!empty($user_id) {

$sql=INSERT INTO profiles (userid, bio, homepage) VALUES($user_id,'Hello world!', 'http://www.stackoverflow.com');
/* or 
 $sql=INSERT INTO profiles (userid, bio, homepage) VALUES(LAST_INSERT_ID(),'Hello   world!', 'http://www.stackoverflow.com'); */
 mysql_query($sql);
};

Referencias
PHP
MYSQL

 3
Author: diEcho,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2011-03-03 09:20:55

¿Qué pasaría, si desea crear muchos de estos registros (para registrar 10 usuarios, no solo uno)? Encuentro la siguiente solución (solo 5 consultas):

Paso I: Cree una tabla temporal para almacenar nuevos datos.

CREATE TEMPORARY TABLE tmp (id bigint(20) NOT NULL, ...)...;

A continuación, rellene esta tabla con valores.

INSERT INTO tmp (username, password, bio, homepage) VALUES $ALL_VAL

Aquí, en lugar de $ALL_VAL se coloca una lista de valores: ('test1', 'test1', 'bio1', 'home1'),...,('testn','testn','bion','homen')

Paso II: Enviar datos al 'usuario' tabla.

INSERT IGNORE INTO users (username, password)
SELECT username, password FROM tmp;

Aquí, se puede usar "IGNORAR", si permite que algunos usuarios ya estén dentro. Opcionalmente, puede usar la ACTUALIZACIÓN similar al paso III, antes de este paso, para encontrar a los usuarios que ya están dentro (y marcarlos en la tabla tmp). Aquí suppouse, ese nombre de usuario se declara como PRIMARY en la tabla de usuarios.

Paso III: Aplicar actualización para leer todos los usuarios id de usuarios a la tabla tmp. ESTE ES UN PASO ESENCIAL.

UPDATE tmp JOIN users ON tmp.username=users.username SET tmp.id=users.id

Paso IV: Crear otro table, useing read id for users

INSERT INTO profiles (userid, bio, homepage) 
SELECT id, bio, homepage FROM tmp
 3
Author: Zasega Anonimno,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2015-09-25 01:44:05

Echa un vistazo a mysql_insert_id ()

Aquí la documentación: http://in.php.net/manual/en/function.mysql-insert-id.php

 2
Author: Daniel Kutik,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2011-03-03 09:21:57

Esta es la forma en que lo hice para un proyecto uni, funciona bien, probablemente no es seguro tho

$dbhost = 'localhost';
$dbuser = 'root';
$dbpass = '';
$conn = mysql_connect($dbhost, $dbuser, $dbpass);

$title =    $_POST['title'];            
$name =     $_POST['name'];         
$surname =  $_POST['surname'];                  
$email =    $_POST['email'];            
$pass =     $_POST['password'];     
$cpass =    $_POST['cpassword'];        

$check = 1;

if (){
}
else{
    $check = 1;
}   
if ($check == 1){

require_once('website_data_collecting/db.php');

$sel_user = "SELECT * FROM users WHERE user_email='$email'";
$run_user = mysqli_query($con, $sel_user);
$check_user = mysqli_num_rows($run_user);

if ($check_user > 0){
    echo    '<div style="margin: 0 0 10px 20px;">Email already exists!</br>
             <a href="recover.php">Recover Password</a></div>';
}
else{
    $users_tb = "INSERT INTO users ". 
           "(user_name, user_email, user_password) ". 
        "VALUES('$name','$email','$pass')";

    $users_info_tb = "INSERT INTO users_info".
           "(user_title, user_surname)".
        "VALUES('$title', '$surname')";

    mysql_select_db('dropbox');
    $run_users_tb = mysql_query( $users_tb, $conn );
    $run_users_info_tb = mysql_query( $users_info_tb, $conn );

    if(!$run_users_tb || !$run_users_info_tb){
        die('Could not enter data: ' . mysql_error());
    }
    else{
        echo "Entered data successfully\n";
    }

    mysql_close($conn);
}

}

 0
Author: SebastianZdroana,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2015-11-15 18:13:21

Solo un comentario sobre tu dicho

Hola, intenté buscar una forma de insertar información en varias tablas en la misma consulta

¿Comes todos tus platos de almuerzo mezclados con bebidas en el mismo tazón?
Supongo que no.

Lo mismo aquí.
Hay cosas que hacemos por separado.
2 insert queries son 2 insert queries. Está bien. No tiene nada de malo. No hay necesidad de machacarlo en uno.
Lo mismo para select. La consulta debe ser sensata y hacer su trabajo. Esa es la sólo razones. Número de consultas no es.

En cuanto a las transacciones, puede usarlas, pero no es TAN importante para el sitio web promedio. Si sucediera una vez al año (si es que alguna vez) que un registro de usuario se rompa, podrás arreglarlo, sin duda.
hay cientos de miles de sitios que ejecutan mysql sin controlador de soporte de transacciones. ¿Has oído hablar de terribles desastres que destrozan estos sitios? Yo tampoco.

Y mysql_insert_id() tiene que ver con transacciones. usted puede incluir en en la transacción de todos los derechos. son cosas diferentes. Alguien planteó esta pregunta de la nada.

 -1
Author: Your Common Sense,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2011-03-03 09:51:44

Para la DOP puede hacer esto

$stmt1 = "INSERT INTO users (username, password) VALUES('test', 'test')"; 
$stmt2 = "INSERT INTO profiles (userid, bio, homepage) VALUES('LAST_INSERT_ID(),'Hello world!', 'http://www.stackoverflow.com')";

$sth1 = $dbh->prepare($stmt1);
$sth2 = $dbh->prepare($stmt2);

BEGIN;
$sth1->execute (array ('test','test'));
$sth2->execute (array ('Hello world!','http://www.stackoverflow.com'));
COMMIT;
 -3
Author: ocnet,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-09-13 09:44:03