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से ऑटो-इंक्रीमेंट कैसे दे सकता हूं ?usersuseridprofile


8
आप लेन-देन के बारे में सीखना चाहते हैं।
विचल

जवाबों:


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()स्वत: संचय मूल्यों का पुन: उपयोग करने के लिए एक नज़र है ।

संपादित करें: आपने कहा कि " इस समय के बाद यह पता लगाने की कोशिश कर रहा है, यह अभी भी काम नहीं कर रहा है। क्या मैं बस एक जनरेट की गई आईडी को $ var में नहीं डाल सकता और उस $ var को सभी MySQL कमांड में डाल सकता हूँ? "

मुझे विस्तार से बताएं: यहां 3 संभावित तरीके हैं:

  1. ऊपर दिए गए कोड में आप देख सकते हैं। यह सब MySQL में करता है, और LAST_INSERT_ID() दूसरे बयान में स्वचालित रूप से ऑटोइनक्रिममेंट-कॉलम का मूल्य होगा जो पहले बयान में डाला गया था।

    दुर्भाग्य से, जब दूसरा स्टेटमेंट स्वयं एक तालिका में एक ऑटो-इन्क्रीमेंट कॉलम के साथ पंक्तियाँ सम्मिलित करता है, तो LAST_INSERT_ID()उसे तालिका 2 से अपडेट किया जाएगा, और तालिका 1 नहीं। यदि आपको अभी भी तालिका 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]

चेतावनी

जो भी आप इसे चुनते हैं, उसे हल करने का तरीका, आपको यह तय करना होगा कि क्या होना चाहिए निष्पादन को प्रश्नों के बीच बाधित किया जाना चाहिए (उदाहरण के लिए, आपका डेटाबेस-सर्वर क्रैश)। यदि आप "कुछ समाप्त हो गए हैं, तो अन्य नहीं" के साथ रह सकते हैं, पर पढ़ें नहीं।

यदि आप निर्णय लेते हैं "या तो सभी प्रश्न समाप्त होते हैं, या कोई भी समाप्त नहीं होता है - मुझे कुछ तालिकाओं में पंक्तियाँ नहीं चाहिए, लेकिन दूसरों में कोई मिलान पंक्तियाँ नहीं हैं, मैं हमेशा चाहता हूँ कि मेरा डेटाबेस तालमेल लगातार बना रहे", आपको लेन-देन में सभी कथनों को लपेटने की आवश्यकता है। इसलिए मैंने BEGINऔर COMMITयहाँ का उपयोग किया ।

अगर आपको अधिक जानकारी चाहिए तो फिर से टिप्पणी करें :)


3
और क्या होगा यदि मैं 2 से अधिक तालिकाओं में सम्मिलित करना चाहता हूं, और मैं चाहता हूं कि अन्य सभी के पास एक अद्वितीय आईडी और उपयोगकर्ता आईडी हो? क्या यह संभव है?
Jay Wit

आप मूल तालिका से MySQL चर में last_insert_id डाल सकते हैं , और अपने सभी अन्य तालिकाओं में उस चर का उपयोग कर सकते हैं। एक संग्रहीत प्रक्रिया का उपयोग करने के लिए f00 का सुझाव और भी अधिक समझ में आता है यदि आप एक समय में बहुत सारी तालिका में हेरफेर करने जा रहे हैं।
कोनरक

3
@ जय बुद्धि: मैंने जवाब अपडेट किया। 'वे 3' बताते हैं कि आप वास्तव में आईडी को एक चर में डाल सकते हैं और इसे सभी MySQL कमांड में पुन: उपयोग कर सकते हैं, लेकिन यदि आप चाहते हैं कि आपके डीबी किसी दुर्घटना के मामले में सुसंगत रहें, तो आपको लेनदेन के बारे में पढ़ना चाहिए।
कोनरक

3
निश्चित रूप से, उन्हें SELECT, UPDATE, INSERT और DELETE की तरह MySQL स्टेटमेंट्स स्वीकार किए जाते हैं। पहले थोड़ा परीक्षण करें, और यदि सब कुछ ठीक है, तो आप जाने के लिए अच्छे हैं।
कोनरक

2
@Konerak @mysql_variablesतैयार बयानों के साथ संयोजन के साथ इन कई एसक्यूएल बयानों का उपयोग करने के बारे में कोई सुझाव ?
फर्नांडो सिल्वा

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, किसी भी सुझाव का उपयोग कर रहा हूँ?
जय विट्

1
sql वक्तव्यों के एक लंबे सेट की तरह दिखता है
मेलबॉर्न

1
@JayWit: नहीं, ये सभी SQL स्टेटमेंट हैं। प्रक्रियाएं बनाएं, फिर आप कभी भी उपयोग कर सकते हैं। Dev.mysql.com/doc/refman/5.7/en/create-procedure.html
पियरे-ओलिवियर

7

यदि आप ऐसे कई रिकॉर्ड बनाना चाहते हैं (10 उपयोगकर्ताओं को पंजीकृत करने के लिए, केवल एक नहीं)? मैं निम्नलिखित समाधान (सिर्फ 5 क्वेरी) पाते हैं:

चरण I: नए डेटा को संग्रहीत करने के लिए अस्थायी तालिका बनाएं।

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: 'उपयोगकर्ता' तालिका में डेटा भेजें।

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

यहां, "IGNORE" का उपयोग किया जा सकता है, यदि आप कुछ उपयोगकर्ताओं को पहले से ही अंदर होने की अनुमति देते हैं। वैकल्पिक रूप से आप इस चरण से पहले चरण III के समान UPDATE का उपयोग कर सकते हैं, यह पता लगाने के लिए कि उपयोगकर्ता पहले से ही अंदर हैं (और उन्हें tmp तालिका में चिह्नित करें)। यहाँ हम मानते हैं, कि उपयोगकर्ता नाम के रूप में घोषित किया गया हैPRIMARY तालिका के में गया है।

चरण III: सभी उपयोगकर्ताओं को पढ़ने के लिए अद्यतन से उपयोगकर्ताओं को tmp तालिका पर लागू करें। यह आवश्यक कदम है।

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

चरण IV: उपयोगकर्ताओं के लिए रीड आईडी का उपयोग करके एक और तालिका बनाएं

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

1
यह 6 प्रश्न हैं - DROP
मंदिर

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
यह कुछ अवांछित व्यवहार का परिणाम होगा, यदि सर्वर उपयोगकर्ता के निर्माण के बाद क्रैश होता है लेकिन प्रोफ़ाइल निर्माण से पहले।
विचल

@ विचले तो सबसे अच्छा तरीका क्या है ??
डायो

2
@vichle इस कोड में अपने रफ़ लेन-देन को जोड़ें और उस बकवास को पहले ही रोक दें
आपका कॉमन सेंस

3
@Konerak मैं 10 वर्षों से PHP स्क्रिप्ट चला रहा हूं। दोनों में से किसी को भी लाइनों के बीच रुकने की आदत नहीं है। बेहतर होगा कि आप अपने सर्वर की गुणवत्ता को बेहतर बनाने के बारे में सोचें ताकि यह अक्सर दुर्घटनाग्रस्त न हो। यह वेब है, यार। यह फेडरल रिजर्व नहीं है। 100 000 000 सफल लोगों के एक टूटे हुए उपयोगकर्ता पंजीकरण के साथ कुछ भी गलत नहीं है।
आपका कॉमन सेंस

2
इस उदाहरण में, आप सही हो सकते हैं। मेरे कोड का उपयोग हमेशा लेखांकन के लिए किया जाता है - ए में पैसा निकालने और इसे बी में जोड़ते समय नहीं सोचा जाना चाहिए, यह असहनीय है। इसके अलावा, भले ही यह सिर्फ वेब है, एक लेनदेन इतना कठिन / महंगा नहीं है? IMHO, वे अच्छी आदतें बनाते हैं।
कोनरक

3

mysql_insert_id () पर एक नज़र डालें

यहाँ प्रलेखन: http://in.php.net/manual/en/function.mysql-insert-id.php


1
यह फ़ंक्शन डेटाबेस संगति का शैतान है।
विचल

सहमत - एक लेन-देन का उपयोग करना बेहतर समाधान हो सकता है
डैनियल कुटिक

@विच: क्या ऐसा है? मैं अक्सर php का उपयोग नहीं करता हूं, लेकिन मुझे लगा कि यह LAST_INSERT_ID()प्रोग्रामर के लिए कॉल करने का उनका शॉर्टकट था ?
कोनरक

1
सभी प्रश्न लेनदेन हैं। अधिकांश प्रोग्रामिंग भाषाओं में डिफ़ॉल्ट ऑटो कमिटमेंट के लिए है, क्योंकि अधिकांश लेनदेन केवल एक क्वेरी है। Mysql_insert_id () फ़ंक्शन का मतलब तब होता है जब आपने ऑटो कमिट को बंद कर दिया है, लेकिन अक्सर लोगों द्वारा लेन-देन की अवधारणा से परिचित नहीं होने के कारण गलत संदर्भ में उपयोग किया जाता है।
विचल

3
@ आप इस फ़ंक्शन और सभी लेनदेन का उपयोग कर सकते हैं। यह लेन-देन टिप्पणी सवाल के लिए अप्रासंगिक है।
आपका कॉमन सेंस

1

यह एक तरीका है जो मैंने इसे एक uni प्रोजेक्ट के लिए किया था, ठीक काम करता है, संभवतः सुरक्षित थियो नहीं

$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 मेरी टेबल myisam टाइप की हैं। पूर्ण खोज, विरासत और आदत के लिए। मैं जोखिम में हूं, हाँ। एक भयानक (सिद्धांत रूप में) संकट मेरा इंतजार कर रहा है।
आपका कॉमन सेंस

6
आप इतने आक्रामक क्यों हो रहे हैं? मैं सिर्फ यह कह रहा हूं कि लेनदेन यहां जाने का रास्ता है। आप इसे अपने तरीके से करते हैं यदि आप चाहें, तो तथ्य यह है कि लेनदेन इस तरह की स्थिति के लिए बनाया गया था।
विचले

@vichle हाँ, मैं काफी कठोर था, मैं माफी माँगता हूँ। यह तुम्हारा था That function is the devil of database consistency.जिसने लेन-देन किया था , लेन-देन नहीं। मुझे लेन-देन में कुछ भी बुरा नहीं दिख रहा है।
आपका कॉमन सेंस

माफी स्वीकार की जाती है। मेरा मतलब था कि इस समारोह का अक्सर उन लोगों द्वारा दुरुपयोग किया जाता है जो लेनदेन के अस्तित्व के बारे में नहीं जानते हैं। ये लोग भी php समुदाय में काफी हद तक प्रतिष्ठित हैं।
विचले

-4

पीडीओ के लिए आप ऐसा कर सकते हैं

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

ठीक वही है जिसकी मुझे तलाश है।
सुब्रतो बिस्वास
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.