Sisipkan MySQL ke dalam beberapa tabel? (Normalisasi database?)

141

Saya mencoba mencari cara untuk mendapatkan insertinformasi di beberapa tabel dalam kueri yang sama, tetapi ternyata tidak mungkin? Jadi saya ingin melakukannya insertdengan hanya menggunakan beberapa pertanyaan yaitu;

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

Tapi bagaimana saya bisa memberikan kenaikan otomatis iddari users"manual" useridke profiletabel?

Jay Wit
sumber
8
Anda ingin belajar tentang transaksi.
vichle
3
kemungkinan duplikat sql - masukkan ke dalam beberapa tabel dalam satu kueri
Pendamaian Terbatas

Jawaban:

252

Tidak, Anda tidak dapat menyisipkan ke beberapa tabel dalam satu perintah MySQL. Namun Anda dapat menggunakan transaksi.

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;

Lihat LAST_INSERT_ID()untuk menggunakan kembali nilai autoincrement.

Edit: Anda berkata " Setelah sekian lama mencoba mencari tahu, itu masih tidak berhasil. Tidak bisakah saya meletakkan ID yang baru saja dihasilkan di $ var dan meletakkan $ var itu di semua perintah MySQL? "

Izinkan saya menjelaskan: ada 3 kemungkinan cara di sini:

  1. Dalam kode yang Anda lihat di atas. Ini melakukan semuanya di MySQL, dan LAST_INSERT_ID()di pernyataan kedua secara otomatis akan menjadi nilai kolom autoincrement yang disisipkan di pernyataan pertama.

    Sayangnya, ketika pernyataan kedua itu sendiri menyisipkan baris dalam tabel dengan kolom kenaikan otomatis, itu LAST_INSERT_ID()akan diperbarui dengan tabel 2, dan bukan tabel 1. Jika Anda masih membutuhkan tabel 1 setelahnya, kita harus menyimpannya dalam variabel. Ini membawa kita ke cara 2 dan 3:

  2. Akan menyimpan LAST_INSERT_ID()dalam variabel MySQL:

    INSERT ...
    SELECT LAST_INSERT_ID() INTO @mysql_variable_here;
    INSERT INTO table2 (@mysql_variable_here, ...);
    INSERT INTO table3 (@mysql_variable_here, ...);
    
  3. Akan menyimpan LAST_INSERT_ID()dalam variabel php (atau bahasa apa pun yang dapat terhubung ke database, pilihan Anda):

    • INSERT ...
    • Gunakan bahasa Anda untuk mengambil LAST_INSERT_ID(), baik dengan menjalankan pernyataan literal itu di MySQL, atau menggunakan misalnya php mysql_insert_id()yang melakukannya untuk Anda
    • INSERT [use your php variable here]

PERINGATAN

Apa pun cara memecahkan masalah ini yang Anda pilih, Anda harus memutuskan apa yang harus terjadi jika eksekusi diinterupsi di antara kueri (misalnya, server database Anda mogok). Jika Anda bisa hidup dengan "beberapa telah selesai, yang lainnya belum", jangan lanjutkan membaca.

Namun jika Anda memutuskan "apakah semua kueri selesai, atau tidak ada yang selesai - saya tidak ingin baris di beberapa tabel tetapi tidak ada baris yang cocok di tabel lain, saya selalu ingin tabel database saya konsisten", Anda perlu membungkus semua pernyataan dalam transaksi. Itu sebabnya saya menggunakan BEGINdan di COMMITsini.

Komentari lagi jika Anda membutuhkan info lebih lanjut :)

Konerak
sumber
3
Dan bagaimana jika saya ingin memasukkan ke lebih dari 2 tabel, dan saya ingin yang lainnya memiliki id unik dan userid? Apakah itu mungkin?
Jay Wit
Anda bisa meletakkan last_insert_id dari tabel asli di variabel MySQL , dan menggunakan variabel itu di semua tabel Anda yang lain. Saran f00 untuk menggunakan Prosedur Tersimpan akan lebih masuk akal jika Anda akan memanipulasi banyak tabel dalam satu waktu.
Konerak
3
@Jay Wit: Saya memperbarui jawabannya. 'Cara 3' menjelaskan bahwa Anda memang dapat menempatkan ID dalam variabel dan menggunakannya kembali di semua perintah MySQL, tetapi Anda harus membaca tentang transaksi jika Anda ingin db Anda konsisten jika terjadi crash.
Konerak
3
Tentu, mereka menerima pernyataan MySQL, seperti SELECT, UPDATE, INSERT and DELETE. Buat sedikit testscript terlebih dahulu, dan jika semuanya berfungsi dengan baik, Anda siap melakukannya.
Konerak
2
Konerak ada tips tentang cara menggunakan beberapa pernyataan SQL ini @mysql_variablesbersama dengan pernyataan yang disiapkan?
Fernando Silva
18

cukup sederhana jika Anda menggunakan prosedur tersimpan:

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

skrip lengkap:

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;
Jon Black
sumber
2
Maaf, apakah ini PHP? Saya belum pernah melihat yang seperti ini. Saya menggunakan PHP dan MySQL, ada tips?
Jay Wit
1
Sepertinya kumpulan pernyataan sql yang panjang
Melbourne2991
1
@JayWit: Tidak, ini semua adalah pernyataan SQL. Buat prosedurnya, lalu Anda bisa menggunakannya kapan pun Anda mau. Lihat dev.mysql.com/doc/refman/5.7/en/create-procedure.html
Pierre-Olivier Vares
8

Apa yang akan terjadi, jika Anda ingin membuat banyak catatan seperti itu (untuk mendaftarkan 10 pengguna, bukan hanya satu)? Saya menemukan solusi berikut (hanya 5 kueri):

Langkah I: Buat tabel sementara untuk menyimpan data baru.

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

Selanjutnya, isi tabel ini dengan nilai.

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

Di sini, alih-alih $ALL_VALAnda menempatkan daftar nilai: ('test1', 'test1', 'bio1', 'home1'), ..., ('testn', 'testn', 'bion', 'homen')

Langkah II: Kirim data ke tabel 'pengguna'.

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

Di sini, "ABAIKAN" dapat digunakan, jika Anda mengizinkan beberapa pengguna sudah berada di dalam. Opsional Anda dapat menggunakan UPDATE yang mirip dengan langkah III, sebelum langkah ini, untuk menemukan pengguna yang sudah ada di dalamnya (dan tandai di tabel tmp). Disini kita suppouse, username tersebut dideklarasikan seperti PRIMARYpada tabel users.

Langkah III: Terapkan pembaruan untuk membaca semua id pengguna dari pengguna ke tabel tmp. INI ADALAH LANGKAH PENTING.

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

Langkah IV: Buat tabel lain, menggunakan id baca untuk pengguna

INSERT INTO profiles (userid, bio, homepage) 
SELECT id, bio, homepage FROM tmp
Zasega Anonimno
sumber
2
itu adalah 6 pertanyaan - jangan lupa untuk DROP SEMENTARA
Zigulik
3

coba ini

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

Referensi
PHP
MYSQL

diEcho
sumber
2
Ini kemungkinan besar akan menghasilkan beberapa perilaku yang tidak diinginkan jika server macet setelah pembuatan pengguna tetapi sebelum pembuatan profil.
vichle
@Vichle lalu apa cara terbaik ??
diEcho
2
@vichle tambahkan transaksi sialan Anda ke kode ini dan hentikan omong kosong itu
Akal
3
@Konerak Saya menjalankan skrip PHP selama lebih dari 10 tahun. Tak satu pun dari mereka memiliki kebiasaan berhenti di antara garis. Anda sebaiknya memikirkan untuk meningkatkan kualitas server Anda agar tidak sering macet. Ini web, bung. itu bukan Federal Reserve. Tidak ada yang salah dengan satu pendaftaran pengguna rusak 100.000 yang sukses.
Akal Sehat Anda
2
Dalam contoh ini, Anda mungkin benar. Kode saya selalu digunakan untuk akuntansi - pemikiran untuk menghapus uang di A dan tidak menambahkannya di B padahal seharusnya, tidak dapat ditoleransi. Lagipula, biarpun hanya web, transaksinya gak susah / mahal? IMHO, mereka membuat kebiasaan baik.
Konerak
3

lihatlah mysql_insert_id ()

berikut dokumentasinya: http://in.php.net/manual/en/function.mysql-insert-id.php

Daniel Kutik
sumber
1
Fungsi itu adalah setan dari konsistensi database.
vichle
setuju - menggunakan transaksi mungkin merupakan solusi yang lebih baik
Daniel Kutik
@vichle: begitu? Saya tidak sering menggunakan php, tapi saya pikir itu jalan pintas mereka untuk memanggil LAST_INSERT_ID()programmer?
Konerak
1
Semua pertanyaan adalah transaksi. Default dalam sebagian besar bahasa pemrograman adalah melakukan transaksi secara otomatis, karena sebagian besar transaksi hanyalah satu kueri. Fungsi mysql_insert_id () dimaksudkan ketika Anda telah mematikan komit otomatis, tetapi sangat sering digunakan dalam konteks yang salah oleh orang-orang yang tidak terbiasa dengan konsep transaksi.
vichle
3
@dnl Anda dapat menggunakan fungsi ini DAN transaksi saja. komentar transaksi ini tidak relevan dengan pertanyaan.
Akal Sehat Anda
1

Ini adalah cara yang saya lakukan untuk proyek universitas, berfungsi dengan baik, mungkin tidak aman

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

}

SebastianZdroana
sumber
-1

Hanya komentar tentang ucapan Anda

Hai, Saya mencoba mencari cara untuk memasukkan informasi di beberapa tabel dalam kueri yang sama

Apakah Anda makan semua hidangan makan siang yang dicampur dengan minuman di mangkuk yang sama?
Saya kira - tidak.

Sama disini.
Ada hal-hal yang kami lakukan secara terpisah.
2 kueri sisipkan adalah 2 kueri sisipkan. Ya, benar. Tidak ada yang salah dengan itu. Tidak perlu menumbuknya menjadi satu.
Sama untuk pilih. Permintaan harus masuk akal dan melakukan tugasnya. Itulah satu-satunya alasan. Jumlah kueri tidak.

Adapun transaksi - Anda dapat menggunakannya, tetapi itu bukan masalah besar untuk situs web rata-rata. Jika terjadi setahun sekali (jika pernah) satu pendaftaran pengguna rusak, Anda pasti dapat memperbaikinya, tidak diragukan lagi.
ada ratusan ribu situs yang menjalankan mysql tanpa driver pendukung transaksi. Pernahkah Anda mendengar bencana mengerikan yang menghancurkan situs-situs ini? Aku juga tidak.

Dan mysql_insert_id () tidak ada hubungannya dengan transaksi. Anda boleh memasukkannya ke dalam transaksi. hanya masalah yang berbeda. Seseorang mengajukan pertanyaan ini entah dari mana.

Akal Sehat Anda
sumber
Mengapa Anda ingin mengambil risiko harus memperbaiki hal-hal seperti itu padahal mudah dihindari?
vichle
@vichle tabel saya adalah tipe myisam. Demi pencarian teks lengkap, warisan dan kebiasaan. Saya mempertaruhkan, ya. Betapa bahaya (dalam teori) yang mengerikan menunggu saya.
Akal Sehat Anda
6
Kenapa kamu begitu agresif? Saya hanya menyatakan bahwa transaksi adalah cara untuk menuju ke sini. Anda melakukannya dengan cara Anda jika Anda mau, faktanya masih bahwa transaksi dibuat untuk situasi seperti ini.
vichle
@vichle yup, saya cukup kasar, saya minta maaf. Itu milikmu That function is the devil of database consistency.yang membuatnya, bukan transaksi. Saya tidak melihat hal buruk dalam transaksi.
Akal Sehat Anda
Permintaan maaf diterima. Yang saya maksud adalah fungsi tersebut sering disalahgunakan oleh orang-orang yang tidak sadar akan adanya transaksi. Orang-orang ini juga cukup terwakili dalam komunitas php.
vichle
-4

Untuk PDO Anda dapat melakukan ini

$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;
ocnet
sumber
Itulah yang saya cari.
Subroto Biswas