mysql में एक अपडेट और एक क्वेरी को सम्मिलित करने के संबंध में क्वेरी


9

मैं एक उपयोगकर्ता के लिए परिवर्तनों के इतिहास को ट्रैक करना चाहता हूं, ताकि जब भी वह अपना प्रोफ़ाइल बदलता है, तो मुझे इतिहास में पुराने डेटा को संग्रहीत करने और नए डेटा के साथ अपडेट करने की आवश्यकता होती है।

मैं selectपुराने डेटा को प्राप्त करने के लिए, insertइतिहास में ए और अंत में updateडेटा को बदलने के लिए उपयोग कर सकता हूं ।

क्या मैं संग्रहित प्रक्रियाओं, ट्रिगर आदि का उपयोग किए बिना mysql में एक एकल क्वेरी में कर सकता हूं .. जैसे ताले आदि का उपयोग करना .. अगर ऐसा है तो मुझे एक छोटा सा नमूना दें।


1
@ सावरनन: यह प्रश्न +1 के योग्य है क्योंकि यह डीबीए और डेवलपर्स को लेनदेन का उपयोग करने और डेटाबेस के एसीआईडी ​​गुणों का पूरा लाभ उठाने के लिए एक मजबूत अनुस्मारक प्रस्तुत करता है।
रोलैंडमाइसीडीडीबीए

2
@ सावरन: सभी इरादों और उद्देश्यों के लिए, जैक ने केवल प्रशंसनीय जवाब दिया है। वास्तव में, जैक डगलस ने इसे एक अतिरिक्त कदम उठाया और प्रत्येक पंक्ति पर एक रुक-रुक कर आईडी = 10 के साथ जोड़ा गया MVCC सुरक्षा के लिए SELECT ... FOR UPDATE। उनका जवाब जैक को आगे बढ़ाता है और मैं सभी के साथ कह रहा हूं: एक अद्यतन और INSERT नहीं हो सकता है, और न ही कभी भी, एक भी प्रश्न नहीं हो सकता है, वे केवल SQL व्यवहार के लिए एक ही लेन-देन कर सकते हैं जो आपके प्रश्न का प्रस्ताव है।
रोलैंडमाइसीडीडीबीए

जवाबों:


13

एक ही समय में एक ही प्रोफ़ाइल का अद्यतन करने की कोशिश कर किसी अन्य उपयोगकर्ता को अवरुद्ध के जोखिम के बिना ऐसा करने के लिए, आपको यह करना पंक्ति ताला में t1पहले, तो का उपयोग किसी लेन-देन (रोलैंडो अपने प्रश्न का टिप्पणी में बताते हैं):

start transaction;
select id from t1 where id=10 for update;
insert into t2 select * from t1 where id=10;
update t1 set id = 11 where id=10;
commit;

यह बस आईडी = 10 के साथ हर पंक्ति को बंद करने में शानदार है। यह एक +2 होना चाहिए। सब मैं दे सकता है एक +1 है !!!
रोलैंडमाइसीडीडीबीए

1

मैं नहीं मानता कि तीनों कथनों को मिलाने का एक तरीका है। उस के लिए निकटतम बात वास्तव में आपकी मदद नहीं करती है, और यह एक सेट चयन है। आपकी सबसे अच्छी शर्त एक ट्रिगर है। नीचे एक ट्रिगर का एक नमूना है जिसे मैं अक्सर ऐसे ऑडिट ट्रेल (PHP के साथ निर्मित) को बनाए रखने के लिए उपयोग करता हूं:

$trigger = "-- audit trigger --\nDELIMITER $ \n".
    "DROP TRIGGER IF EXISTS `{$prefix}_Audit_Trigger`$\n".
    "CREATE TRIGGER `{$prefix}_Audit_Trigger` AFTER UPDATE ON `$this->_table_name` FOR EACH ROW BEGIN\n";

foreach ($field_defs as $field_name => $field) {
    if ($field_name != $id_name) {
       $trigger .= "IF (NOT OLD.$field_name <=> NEW.$field_name) THEN \n".'INSERT INTO AUDIT_LOG ('.
                    'Table_Name, Row_ID, Field_Name, Old_Value, New_Value, modified_by, DB_User) VALUES'.
                    "\n ('$this->_table_name',OLD.$this->_id_name,'$field_name',OLD.$field_name,NEW.$field_name,".
                    "NEW.modified_by, USER()); END IF;\n";
    }
}
$trigger .= 'END$'."\n".'DELIMITER ;';

-3

मैंने पाया है कि यह क्वेरी SQL और MySQL सर्वर पर काम करती है INSERT INTO t2 SELECT * FROM t1 WHERE id=10; UPDATE t1 SET id=11 WHERE id=10;

आशा है कि यह भविष्य में कुछ और के लिए भी उपयोगी है।


4
यह वास्तव में एक प्रश्न नहीं है। यह वास्तव में दो प्रश्न हैं जिन्हें लेनदेन के रूप में माना जाना चाहिए।
RolandoMySQLDBA

@rolandomysqldba: यह एक क्वेरी के रूप में ठीक काम करता है, जब मैं एप्लिकेशन कोड से एक db सर्वर को भेजता हूं, जहां मैं इस सेट को एक क्वेरी के रूप में मानता हूं। आप ऐसा क्यों कहते हैं?। क्या आप इसे मजबूत कारणों से मना कर सकते हैं ..
सरवनन

2
@saravanan: InnoDB या किसी भी ACID- अनुपालन RDBMS (Oracle, SQLServer, PostreSQL, Sybase, आदि) की नज़र में, उन दो SQL बयानों को एक क्वेरी कहना असंभव है। एक एसीआईडी-अनुपालन डेटाबेस के रूप में उन्हें दो बयानों के रूप में माना जाएगा। डिफ़ॉल्ट रूप से, InnoDB में स्वतः पूर्ण चालू है। पहला बयान, INSERT, एकल लेनदेन के रूप में निष्पादित करेगा। पंक्ति-दर-पंक्ति आधार पर t2 तालिका में मूल डेटा की एक प्रति रखने के लिए मल्टीवेरिंग कॉनएरेसी कंट्रोल (MVCC) डेटा उत्पन्न किया जाएगा। यदि MySQL INSERT के निष्पादन के दौरान क्रैश हो जाता है, तो InnoDB अपनी मूल स्थिति में t2 को रोलबैक करने के लिए MVCC डेटा का उपयोग करता है।
रोलैंडम्यूसीडीडीबीए

1
@ सरवनन: मान लीजिए कि INSERT ने सफलतापूर्वक काम किया। INSERT के परिणामस्वरूप होने वाला डेटा प्रतिबद्ध किया गया है (ऑटोकॉमिट ON के साथ) और MVCC प्रोटेक्टिंग टेबल t2 को छोड़ दिया गया है। जब आप UPDATE करते हैं, MVCC t1 तालिका के विरुद्ध उत्पन्न होता है और UPDATE निष्पादित होता है। यदि MySQL UPDATE के दौरान क्रैश हो जाता है, तो InnoDB UPDATE को रोलबैक करने के लिए t1 पर MVCC डेटा का उपयोग करता है। यहां तक ​​कि अगर UPDATE सिर्फ एक पंक्ति को बदल रहा है, तो एक-में-एक-मेल-की संभावना टी 1 से टी 2 में आईडी 10 के साथ चलती है और आईडी 10 को आईडी 10 में बदलकर आईडी 11 नहीं है। इस अनूठे परिदृश्य को रोकने के लिए, आपको निम्न कार्य करने होंगे ...
RolandoMySQLDBA

@ सावरनन: दो एसक्यूएल स्टेटमेंट को एक ही लेन-देन के रूप में समझें। ऐसा करने का सरल तरीका है: बेगिन; INSERT INTO t2 SELECT * FROM t1 WHERE id = 10; UPDATE t1 SET id = 11 WHERE id = 10; COMMIT; दो SQL कथनों को एक ही लेनदेन के रूप में मानने का सबसे मजबूत कारण यह तथ्य है कि INSERT के लिए बनाया गया MVCC UPDATE के दौरान अस्तित्व में रहेगा। यदि किसी लेन-देन (BEGIN; ... COMMIT; ब्लॉक) के अंदर एक MySQL क्रैश UPDATE के दौरान होना चाहिए तो MVCC एक सुसंगत स्थिति में सभी परिवर्तनों को रोलबैक कर देगा। यदि INSERT और UPDATE दोनों पूर्ण हो जाते हैं, तो MVCC को अंतिम समय में छोड़ दिया जाता है।
रोलैंडमाइसीडीडीबीए
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.