여러 테이블에 MySQL 삽입? (데이터베이스 정규화?)


136

insert동일한 쿼리에서 여러 테이블의 정보를 검색하는 방법을 시도했지만 불가능하다는 것을 알았습니다. 그래서 나는 insert단순히 여러 쿼리를 사용하여 그것을 원합니다 .

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')

하지만 내가 어떻게 자동 증가 줄 수 id로부터 users"수동"으로 userid에 대한 profile테이블을?


8
거래에 대해 배우고 싶습니다.
vichle

3
가능한 SQL
제한된 속죄

답변:


241

아니요, 하나의 MySQL 명령으로 여러 테이블에 삽입 할 수 없습니다. 그러나 거래를 사용할 수 있습니다.

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;

LAST_INSERT_ID()자동 증분 값을 재사용 하는 방법을 살펴보십시오 .

편집 : 당신은 " 이번에 그것을 알아 내려고 시도한 후에도 여전히 작동하지 않습니다. 그냥 방금 생성 된 ID를 $ var에 넣고 그 $ var를 모든 MySQL 명령에 넣을 수 없습니까? "

자세히 설명하겠습니다. 여기에는 3 가지 방법이 있습니다.

  1. 위 코드에서 볼 수 있습니다. 이것은 MySQL에서 모든 작업을 수행하며 LAST_INSERT_ID()in 두 번째 명령문은 자동으로 첫 번째 명령문에 삽입 된 자동 증분 열의 값이됩니다.

    불행히도, 두 번째 명령문 자체가 자동 증가 열이있는 테이블에 행을 삽입 LAST_INSERT_ID()하면 테이블 1이 아니라 테이블 2의 행으로 업데이트됩니다. 이후에 테이블 1의 행이 계속 필요하면이를 저장해야합니다. 변수에서. 이것은 우리를 길 2와 3으로 인도합니다.

  2. LAST_INSERT_ID()MySQL 변수에 재고를 보관합니다 :

    INSERT ...
    SELECT LAST_INSERT_ID() INTO @mysql_variable_here;
    INSERT INTO table2 (@mysql_variable_here, ...);
    INSERT INTO table3 (@mysql_variable_here, ...);
  3. 재고 것 LAST_INSERT_ID()PHP는 변수 (또는 당신의 선택의 데이터베이스에 연결할 수있는 모든 언어)에서 :

    • INSERT ...
    • 언어를 사용하여 LAST_INSERT_ID()MySQL에서 리터럴 문을 실행하거나 예를 들어 PHP를 사용하여을 mysql_insert_id()검색하십시오.
    • INSERT [use your php variable here]

경고

이 문제를 해결하는 방법에 관계없이 쿼리간에 실행이 중단 될 경우 어떻게해야하는지 결정해야 합니다 (예 : 데이터베이스 서버 충돌). "일부는 끝났고 그렇지 않은 사람"과 함께 살 수 있다면 계속 읽으십시오.

그러나 "모든 쿼리가 완료되거나 완료되지 않습니다. 일부 테이블에는 행을 원하지 않지만 다른 테이블에는 일치하는 행을 원하지 않으면 항상 데이터베이스 테이블이 일관성을 유지하기를 원할 경우"모든 명령문을 트랜잭션에 래핑해야합니다. 내가 사용하는 이유 BEGINCOMMIT여기.

더 많은 정보가 필요한 경우 다시 의견 :)


3
그리고 두 개 이상의 테이블에 삽입하고 다른 모든 테이블에 고유 ID와 사용자 ID를 갖기를 원한다면 어떻게해야합니까? 가능합니까?
Jay Wit

원본 테이블의 last_insert_id를 MySQL 변수 에 넣고 다른 모든 테이블에서 해당 변수를 사용할 수 있습니다. 한 번에 많은 테이블을 조작하려는 경우 저장 프로 시저 사용에 대한 f00의 제안이 더 의미가 있습니다.
Konerak

3
@Jay Wit : 답변을 업데이트했습니다. 'Way 3'은 실제로 ID를 변수에 넣고 모든 MySQL 명령에서 재사용 할 수 있다고 설명하지만 충돌시 DB가 일관성을 유지하려면 트랜잭션에 대해 읽어야합니다.
Konerak

3
물론 SELECT, UPDATE, INSERT 및 DELETE와 같이 MySQL 문이 허용됩니다. 먼저 약간의 테스트 스크립트를 작성하고 모든 것이 올바르게 작동하면 잘 진행하십시오.
Konerak

2
@Konerak이 여러 SQL 문 @mysql_variables을 준비된 문과 함께 사용하는 방법에 대한 팁이 있습니까?
Fernando Silva

17

저장 프로 시저를 사용하는 경우 매우 간단합니다.

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

전체 스크립트 :

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;

2
죄송하지만이 PHP입니까? 나는 이런 것을 본 적이 없다. PHP와 MySQL을 사용하고 있습니까?
Jay Wit

1
긴 SQL 문 집합처럼 보인다
Melbourne2991

1
@JayWit : 아니요. 모두 SQL 문입니다. 절차를 작성하면 언제든지 사용할 수 있습니다. 참조 dev.mysql.com/doc/refman/5.7/en/create-procedure.html
피에르 - 올리비에 Vares에게

7

이러한 레코드를 여러 개 만들려면 어떻게해야합니까 (하나가 아닌 10 명의 사용자를 등록하기 위해)? 다음과 같은 해결책을 찾았습니다 (단지 5 개의 쿼리).

1 단계 : 새 데이터를 저장할 임시 테이블을 만듭니다.

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

다음으로이 테이블을 값으로 채우십시오.

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

여기 $ALL_VAL에 값 목록을 배치하는 대신 ( 'test1', 'test1', 'bio1', 'home1'), ..., ( 'testn', 'testn', 'bion', 'homen')

단계 II : 'user'테이블로 데이터를 보냅니다.

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

여기서 일부 사용자가 이미 내부에있는 것을 허용하는 경우 "IGNORE"를 사용할 수 있습니다. 선택적으로이 단계 전에 단계 III과 유사한 UPDATE를 사용하여 이미 내부에있는 사용자를 찾아서 tmp 테이블에 표시 할 수 있습니다. 여기서는 사용자 이름이 PRIMARYusers 테이블에서 선언 된 것으로 가정 합니다.

3 단계 : 업데이트를 적용하여 모든 사용자 ID를 사용자에서 tmp 테이블로 읽습니다. 이것은 필수 단계입니다.

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

IV 단계 : 사용자의 읽기 ID를 사용하여 다른 테이블 작성

INSERT INTO profiles (userid, bio, homepage) 
SELECT id, bio, homepage FROM tmp

1
그것은 6 개의 질문입니다-임시 삭제를 잊지 마세요
Zigulik

3

이 시도

$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);
};


PHP MYSQL 참조


2
이는 사용자 작성 후 또는 프로파일 작성 전에 서버가 충돌하는 경우 원치 않는 동작이 발생할 가능성이 큽니다.
vichle

@ Vichle 그렇다면 가장 좋은 방법은 무엇입니까 ??
diEcho

2
@vichle는이 코드에 과감한 거래를 추가하고 그 말도 안되는 것을 막으십시오
Common Sense

3
@Konerak 저는 10 년 넘게 PHP 스크립트를 실행하고 있습니다. 둘 다 라인 사이를 멈추는 습관이 없습니다. 자주 충돌하지 않도록 서버 품질을 향상시키는 것이 좋습니다. 웹이야, 친구 연방 준비 은행이 아닙니다. 100 000 000 개의 성공적인 사용자 등록 중 하나라도 잘못되었습니다.
당신의 상식

2
이 예에서는 당신이 옳을 수도 있습니다. 내 코드는 항상 회계에 사용됩니다 .A에서 돈을 제거하고 B에 추가하지 않는 생각은 참을 수 없습니다. 게다가 웹 일지라도 거래가 그렇게 어렵거나 비싸지 않은가? IMHO, 그들은 좋은 습관을 만듭니다.
Konerak

3

mysql_insert_id ()를 살펴보십시오.

여기에 문서 : http://in.php.net/manual/en/function.mysql-insert-id.php


1
이 기능은 데이터베이스 일관성의 문제입니다.
vichle

동의-거래를 사용하는 것이 더 나은 솔루션 일 수 있습니다
Daniel Kutik

@vichle : 그렇습니까? 나는 자주 PHP를 사용하지 않지만 LAST_INSERT_ID()프로그래머 를 부르는 것이 지름길이라고 생각 했습니까?
Konerak

1
모든 쿼리는 트랜잭션입니다. 대부분의 프로그래밍 언어에서 기본값은 트랜잭션을 자동 커밋하는 것입니다. 대부분의 트랜잭션은 하나의 쿼리 일뿐입니다. mysql_insert_id () 함수는 자동 커밋을 끈 경우를위한 것이지만 트랜잭션 개념에 익숙하지 않은 사람들이 잘못된 컨텍스트에서 자주 사용합니다.
vichle

3
@dnl이 함수와 트랜잭션을 사용할 수 있습니다. 이 거래 설명은 질문과 관련이 없습니다.
당신의 상식

1

이것이 내가 유니 프로젝트를 위해했던 방식이며, 잘 작동하며 안전하지 않을 것입니다.

$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);
}

}


-1

당신의 말에 대한 언급

안녕하세요, 같은 쿼리에서 여러 테이블에 정보를 삽입하는 방법을 검색했습니다.

같은 그릇에 음료수와 혼합 된 모든 점심 요리를 먹습니까?
나는 생각한다.

여기도 마찬가지입니다.
우리가 별도로하는 일이 있습니다.
2 개의 삽입 쿼리는 2 개의 삽입 쿼리입니다. 괜찮아 아무 문제가 없습니다. 한 번에 으 깨지 않아도됩니다.
선택과 동일합니다. 쿼리는 합리적이어야하며 제대로 작동해야합니다. 그게 유일한 이유입니다. 쿼리 수가 없습니다.

거래에 관해서는-당신은 그들을 사용할 수 있지만, 평균 웹 사이트에 그렇게 큰 것은 아닙니다. 일년에 한 번 (있는 경우) 한 명의 사용자 등록이 중단 된 경우 문제를 해결할 수 있습니다.
트랜잭션 지원 드라이버없이 mysql을 실행하는 수십만 개의 사이트가 있습니다. 이 사이트들을 파괴하는 끔찍한 재난에 대해 들어 보셨습니까? 나도

그리고 mysql_insert_id ()는 트랜잭션과 관련이 없습니다. 당신은 거래에 모든 권리를 포함시킬 수 있습니다. 그것은 단지 다른 문제입니다. 누군가이 질문을 아무 데나 제기하지 않았습니다.


쉽게 피할 수있을 때 왜 그런 것들을 고칠 필요가 있는가?
vichle

@ vichle 내 테이블은 myisam 유형입니다. 전문 검색, 레거시 및 습관을 위해. 위험합니다. (이론적으로) 끔찍한 위험이 나를 기다리고 있습니다.
당신의 상식

6
왜 그렇게 공격적입니까? 나는 단지 거래가 여기에가는 길이라고 말하고있다. 당신이 원한다면 당신은 당신의 길을 간다. 사실 이런 종류의 상황을 위해 거래가 만들어 졌다는 것이 사실이다.
vichle

@ vichle yup, 나는 매우 가혹했습니다. 죄송합니다. 그것은 That function is the devil of database consistency.거래가 아니라 당신의 것이 었 습니다. 나는 거래에서 나쁘지 않은 것을 본다.
당신의 상식

사과 받음. 내가 의미하는 것은 거래의 존재를 모르는 사람들이 종종 그 기능을 오용한다는 것입니다. 이 사람들은 PHP 커뮤니티에서도 과장되어 있습니다.
vichle

-4

PDO의 경우이 작업을 수행 할 수 있습니다

$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;

그것이 바로 내가 찾는 것입니다.
Subroto Biswas
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.