2012-09-24 18 views
73

मुझसे पूछा गया है कि क्या मैं एक MySQL डेटाबेस में रिकॉर्ड्स में परिवर्तनों का ट्रैक रख सकता हूं। तो जब एक क्षेत्र बदल दिया गया है, तो पुराने बनाम नया उपलब्ध है और यह तिथि हुई है। क्या ऐसा करने के लिए कोई सुविधा या सामान्य तकनीक है?क्या रिकॉर्ड्स में बदलावों के इतिहास को ट्रैक करने के लिए कोई MySQL विकल्प/सुविधा है?

यदि ऐसा है, तो मैं ऐसा कुछ करने की सोच रहा था। बदलाव नामक एक टेबल बनाएं। इसमें मास्टर टेबल के समान फ़ील्ड होंगे लेकिन पुराने और नए के साथ उपसर्ग किया जाएगा, लेकिन केवल उन फ़ील्ड के लिए जो वास्तव में बदले गए थे और इसके लिए TIMESTAMP थे। इसे एक आईडी के साथ अनुक्रमित किया जाएगा। इस तरह, प्रत्येक रिकॉर्ड के इतिहास को दिखाने के लिए एक चयन रिपोर्ट चलाया जा सकता है। क्या यह एक अच्छी विधि है? धन्यवाद!

+0

संभावित डुप्लिकेट [MySQL में रिकॉर्ड अपडेट के इतिहास रखने के लिए कैसे?] (Http://stackoverflow.com/questions/2536819/ कैसे-से-इतिहास-ऑफ-रिकॉर्ड-अपडेट-इन-माइस्क्ल) – Gajus

उत्तर

47

यह सूक्ष्म है।

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

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

इसके बजाए, आप समय के साथ अपने स्कीमा डिज़ाइन में बदलाव की अवधारणा को सेंक सकते हैं (यह दूसरा विकल्प है जो केथनंजन सुझाता है)। यह आपके आवेदन में बदलाव है, निश्चित रूप से व्यापार तर्क और दृढ़ता स्तर पर, इसलिए यह मामूली नहीं है।

उदाहरण के लिए, अगर आप इस तरह एक मेज है:

CUSTOMER 
--------- 
CUSTOMER_ID PK 
CUSTOMER_NAME 
CUSTOMER_ADDRESS 

और आप समय के साथ ट्रैक रखने के लिए चाहता था, आप इसे में संशोधन देंगी:

CUSTOMER 
------------ 
CUSTOMER_ID   PK 
CUSTOMER_VALID_FROM PK 
CUSTOMER_VALID_UNTIL PK 
CUSTOMER_STATUS 
CUSTOMER_USER 
CUSTOMER_NAME 
CUSTOMER_ADDRESS 

हर बार जब आप चाहते हैं कि रिकॉर्ड अपडेट करने के बजाए ग्राहक रिकॉर्ड बदलें, आप वर्तमान रिकॉर्ड पर VALID_UNTIL को अभी() पर सेट करें, और एक VALID_FROM (अब) और एक शून्य VALID_UNTIL के साथ एक नया रिकॉर्ड डालें। आपने वर्तमान उपयोगकर्ता की लॉगिन आईडी में "CUSTOMER_USER" स्थिति सेट की है (यदि आपको इसे रखने की आवश्यकता है)। यदि ग्राहक को हटाने की आवश्यकता है, तो आप इसे इंगित करने के लिए CUSTOMER_STATUS ध्वज का उपयोग करें - आप इस तालिका से रिकॉर्ड कभी भी हटा नहीं सकते हैं।

इस तरह, आप हमेशा यह देख सकते हैं कि ग्राहक तालिका की स्थिति किसी दिए गए दिनांक के लिए क्या थी - पता क्या था? क्या उन्होंने नाम बदल दिया है? समान मान्य_from और valid_until तिथियों वाली अन्य तालिकाओं में शामिल होने से, आप ऐतिहासिक रूप से पूरी तस्वीर का पुनर्निर्माण कर सकते हैं। वर्तमान स्थिति को खोजने के लिए, आप एक शून्य VALID_UNTIL दिनांक वाले रिकॉर्ड्स की खोज करते हैं।

यह अनावश्यक है (सख्ती से बोल रहा है, आपको वैध_फ्रेम की आवश्यकता नहीं है, लेकिन यह प्रश्नों को थोड़ा आसान बनाता है)। यह आपके डिज़ाइन और आपके डेटाबेस तक पहुंच को जटिल बनाता है। लेकिन यह दुनिया को पुनर्निर्माण करने में बहुत आसान बनाता है।

+0

लेकिन यह उन फ़ील्ड के लिए डुप्लिकेट डेटा जोड़ देगा जो अपडेट नहीं किए गए हैं? इसका प्रबंधन कैसे करें? – itzmukeshy7

+0

रिपोर्ट पीढ़ी के लिए दूसरी दृष्टिकोण समस्या उत्पन्न होने पर एक ग्राहक रिकॉर्ड को एक समय में संपादित किया जाता है, यह पहचानना मुश्किल होता है कि कोई विशेष प्रविष्टि एक ही ग्राहक या अलग से संबंधित है या नहीं। –

+0

सबसे अच्छा सुझाव मैंने अभी तक इस समस्या को देखा है – Worthy7

13

आप इसे हल करने के लिए ट्रिगर्स बना सकते हैं। Here is a tutorial to do so (संग्रहीत लिंक)।

डेटाबेस में कमी और नियमों की स्थापना एक ही कार्य को संभालने के लिए के बाद से यह एक अलग प्रश्न है कि विशेष कोड के सभी नजरअंदाज लिखने से एक और डेवलपर पाएगा विशेष कोड लिखने से बेहतर है और अपने डेटाबेस छोड़ सकता खराब डेटा अखंडता के साथ।

लंबे समय तक मैं एक स्क्रिप्ट का उपयोग करके दूसरी तालिका में जानकारी कॉपी कर रहा था क्योंकि MySQL उस समय ट्रिगर्स का समर्थन नहीं करता था। अब मुझे यह सब कुछ ट्रैक रखने में अधिक प्रभावी होने के लिए ट्रिगर मिला है।

यह ट्रिगर एक पुराने मान को इतिहास तालिका में कॉपी करेगा यदि यह बदल जाता है जब कोई पंक्ति संपादित करता है। Editor ID और last mod मूल तालिका में संग्रहीत होते हैं जब भी कोई उस पंक्ति को संपादित करता है; समय से मेल खाता है जब इसे अपने वर्तमान रूप में बदल दिया गया था।

DROP TRIGGER IF EXISTS history_trigger $$ 

CREATE TRIGGER history_trigger 
BEFORE UPDATE ON clients 
    FOR EACH ROW 
    BEGIN 
     IF OLD.first_name != NEW.first_name 
     THEN 
       INSERT INTO history_clients 
        (
         client_id , 
         col   , 
         value  , 
         user_id  , 
         edit_time 
        ) 
        VALUES 
        (
         NEW.client_id, 
         'first_name', 
         NEW.first_name, 
         NEW.editor_id, 
         NEW.last_mod 
        ); 
     END IF; 

     IF OLD.last_name != NEW.last_name 
     THEN 
       INSERT INTO history_clients 
        (
         client_id , 
         col   , 
         value  , 
         user_id  , 
         edit_time 
        ) 
        VALUES 
        (
         NEW.client_id, 
         'last_name', 
         NEW.last_name, 
         NEW.editor_id, 
         NEW.last_mod 
        ); 
     END IF; 

    END; 
$$ 

एक अन्य समाधान एक संशोधन क्षेत्र रखने के लिए और बचाने के लिए पर इस क्षेत्र को अद्यतन करने के लिए किया जाएगा। आप तय कर सकते हैं कि अधिकतम नवीनतम संशोधन है, या 0 सबसे हालिया पंक्ति है। यह आप पर निर्भर है।

115

यहाँ यह करने के लिए एक सरल तरीका है:

सबसे पहले, आप ट्रैक करने के लिए (नीचे उदाहरण क्वेरी) चाहते प्रत्येक डेटा तालिका के लिए एक इतिहास तालिका बनाने के। इस तालिका में डेटा तालिका में प्रत्येक पंक्ति पर किए गए प्रत्येक सम्मिलन, अद्यतन और क्वेरी के लिए एक प्रविष्टि होगी।

इतिहास तालिका की संरचना तीन अतिरिक्त कॉलम को छोड़कर ट्रैक की गई डेटा तालिका के समान होगी: ऑपरेशन को संग्रहीत करने के लिए एक कॉलम (चलिए इसे 'एक्शन' कहते हैं), ऑपरेशन की तिथि और समय , और अनुक्रम संख्या ('संशोधन') को संग्रहीत करने के लिए एक कॉलम, जो प्रति ऑपरेशन में वृद्धि करता है और डेटा तालिका के प्राथमिक कुंजी कॉलम द्वारा समूहीकृत किया जाता है।

इस अनुक्रमिक व्यवहार को करने के लिए प्राथमिक कुंजी कॉलम और संशोधन कॉलम पर दो कॉलम (समग्र) अनुक्रमणिका बनाई गई है। ध्यान दें कि यदि आप इतिहास तालिका द्वारा उपयोग किए गए इंजन को केवल इस शैली में अनुक्रमित कर सकते हैं, तो MyISAM (See 'MyISAM Notes' on this page)

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

CREATE TABLE MyDB.data_history LIKE MyDB.data; 

ALTER TABLE MyDB.data_history MODIFY COLUMN primary_key_column int(11) NOT NULL, 
    DROP PRIMARY KEY, ENGINE = MyISAM, ADD action VARCHAR(8) DEFAULT 'insert' FIRST, 
    ADD revision INT(6) NOT NULL AUTO_INCREMENT AFTER action, 
    ADD dt_datetime DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP AFTER revision, 
    ADD PRIMARY KEY (primary_key_column, revision); 

और फिर आप ट्रिगर बना:।।

DROP TRIGGER IF EXISTS MyDB.data__ai; 
DROP TRIGGER IF EXISTS MyDB.data__au; 
DROP TRIGGER IF EXISTS MyDB.data__bd; 

CREATE TRIGGER MyDB.data__ai AFTER INSERT ON MyDB.data FOR EACH ROW 
    INSERT INTO MyDB.data_history SELECT 'insert', NULL, NOW(), d.* 
    FROM MyDB.data AS d WHERE d.primary_key_column = NEW.primary_key_column; 

CREATE TRIGGER MyDB.data__au AFTER UPDATE ON MyDB.data FOR EACH ROW 
    INSERT INTO MyDB.data_history SELECT 'update', NULL, NOW(), d.* 
    FROM MyDB.data AS d WHERE d.primary_key_column = NEW.primary_key_column; 

CREATE TRIGGER MyDB.data__bd BEFORE DELETE ON MyDB.data FOR EACH ROW 
    INSERT INTO MyDB.data_history SELECT 'delete', NULL, NOW(), d.* 
    FROM MyDB.data AS d WHERE d.primary_key_column = OLD.primary_key_column; 

और आपका काम हो गया अब, सभी आवेषण, 'MyDb.dat में अद्यतन और हटाए गए एक MyDb.data_history 'में रिकॉर्ड किए जाएंगे', आप इस प्रकार का इतिहास तालिका दे रही है (ऋण काल्पनिक 'data_columns' कॉलम)

ID revision action data columns.. 
1  1   'insert' ....   initial entry for row where ID = 1 
1  2   'update' ....   changes made to row where ID = 1 
2  1   'insert' ....   initial entry, ID = 2 
3  1   'insert' ....   initial entry, ID = 3 
1  3   'update' ....   more changes made to row where ID = 1 
3  2   'update' ....   changes made to row where ID = 3 
2  2   'delete' ....   deletion of row where ID = 2 

अद्यतन करने के लिए अद्यतन से किसी दिए गए स्तंभ या स्तंभों के लिए परिवर्तन प्रदर्शित करने के लिए, प्राथमिक कुंजी और अनुक्रम कॉलम पर आपको इतिहास तालिका में शामिल होने की आवश्यकता होगी।आप इस उद्देश्य के लिए एक दृश्य बना सकते हैं, उदाहरण के लिए:

CREATE VIEW data_history_changes AS 
    SELECT t2.dt_datetime, t2.action, t1.primary_key_column as 'row id', 
    IF(t1.a_column = t2.a_column, t1.a_column, CONCAT(t1.a_column, " to ", t2.a_column)) as a_column 
    FROM MyDB.data_history as t1 INNER join MyDB.data_history as t2 on t1.primary_key_column = t2.primary_key_column 
    WHERE (t1.revision = 1 AND t2.revision = 1) OR t2.revision = t1.revision+1 
    ORDER BY t1.primary_key_column ASC, t2.revision ASC 
+3

मुझे वास्तव में यह समाधान पसंद है। हालांकि यदि आपकी मुख्य तालिका में कोई प्राथमिक कुंजी नहीं है या आप नहीं जानते कि प्राथमिक क्या है, तो यह थोड़ा मुश्किल है। – Umingo

+1

वाह !!! ये जबरदस्त है। बेकार काम किया! –

+0

मैंने हाल ही में एक परियोजना के लिए इस समाधान का उपयोग कर एक समस्या में भाग लिया, क्योंकि मूल तालिका से सभी इंडेक्स को इतिहास तालिका में कॉपी किया गया है (तालिका कैसे बनाएं ... पसंद है .... काम करता है)। इतिहास तालिका पर अद्वितीय इंडेक्स होने से INSERT क्वेरी को बाद में ट्रिगर के लिए ट्रिगर के कारण उत्पन्न हो सकता है, इसलिए उन्हें हटा दिया जाना चाहिए। php स्क्रिप्ट में मुझे लगता है कि इस सामग्री करता है, मैं नव निर्मित इतिहास टेबल पर किसी भी अद्वितीय अनुक्रमणिका के लिए क्वेरी है (के साथ "data_table से शो सूचकांक जहां KEY_NAME! = 'प्राथमिक' और Non_unique = 0"), और फिर उन्हें हटा दें। –

4

यहाँ कैसे हम इसे हल

एक उपयोगकर्ता तालिका इस

Users 
------------------------------------------------- 
id | name | address | phone | email | created_on | updated_on 

और व्यवसाय की आवश्यकता की तरह दिखाई देता बदल गया है और हम थे किसी भी उपयोगकर्ता के पास पिछले सभी पते और फ़ोन नंबरों की जांच करने की आवश्यकता है। नई स्कीमा इस

Users (the data that won't change over time) 
------------- 
id | name 

UserData (the data that can change over time and needs to be tracked) 
------------------------------------------------- 
id | id_user | revision | city | address | phone | email | created_on 
1 | 1  | 0  | NY | lake st | 9809 | @long | 2015-10-24 10:24:20 
2 | 1  | 2  | Tokyo| lake st | 9809 | @long | 2015-10-24 10:24:20 
3 | 1  | 3  | Sdny | lake st | 9809 | @long | 2015-10-24 10:24:20 
4 | 2  | 0  | Ankr | lake st | 9809 | @long | 2015-10-24 10:24:20 
5 | 2  | 1  | Lond | lake st | 9809 | @long | 2015-10-24 10:24:20 

की तरह लग रहा है, हम संशोधन DESC और सीमा के साथ UserData के लिए खोज 1

समय की एक निश्चित अवधि के बीच एक उपयोगकर्ता के पते प्राप्त करने के लिए किसी भी उपयोगकर्ता की वर्तमान पता ढूंढने के लिए हम create_on bewteen (date1, date 2)

+0

होना चाहिए यह एक ऐसा समाधान है जिसे मैं चाहता हूं लेकिन मैं जानना चाहता हूं कि आप इस तालिका में ट्रिगर का उपयोग करके id_user कैसे डाल सकते हैं ? –

+1

'id_user = 1' के' संशोधन = 1' के साथ क्या हुआ? सबसे पहले मैंने सोचा था कि आपकी गिनती '0,2,3 थी, ... 'लेकिन फिर मैंने देखा कि' id_user = 2' के लिए संशोधन गणना '0,1 है, ...' – Pathros

+0

आपको आवश्यकता नहीं है 'आईडी' और' id_user' कॉलम'। बस 'आईडी' (उपयोगकर्ता आईडी) और' संशोधन 'की समूह आईडी का उपयोग करें। – Gajus

0

का उपयोग करने का सीधा तरीका टेबल पर ट्रिगर्स बनाना है। कुछ स्थितियों या मैपिंग विधियों को सेट करें। जब अद्यतन या हटा होता है, तो यह स्वचालित रूप से 'परिवर्तन' तालिका में डालेगा।

लेकिन सबसे बड़ा हिस्सा यह है कि अगर हमें बहुत सारे कॉलम और टेबल की बहुत सारी चीज़ें मिलती हैं। हमें प्रत्येक तालिका के प्रत्येक कॉलम का नाम टाइप करना होगा। जाहिर है, यह समय बर्बाद है।

इसे और अधिक भव्य तरीके से संभालने के लिए, हम स्तंभों के नाम को पुनः प्राप्त करने के लिए कुछ प्रक्रियाएं या कार्य बना सकते हैं।

हम इसे करने के लिए बस तृतीय-पक्ष टूल का भी उपयोग कर सकते हैं। यहां, मैं एक जावा प्रोग्राम Mysql Tracker

+0

मैं अपने माइस्क्ल ट्रैकर का उपयोग कैसे कर सकता हूं? – webchun

+0

1. सुनिश्चित करें कि आपके पास प्रत्येक तालिका में प्राथमिक कुंजी के रूप में एक आईडी कॉलम है। 2. जावा फ़ाइल को स्थानीय (या आईडीई) पर कॉपी करें 3. अपनी डेटाबेस कॉन्फ़िगरेशन और संरचना के अनुसार लाइन 9-15 से स्थिर चर को संपादित करें और संपादित करें। 4. पार्स और जावा फ़ाइल चलाएं 5. कंसोल लॉग कॉपी करें और इसे MySQL कमांड के रूप में निष्पादित करें – goforu

2

बस मेरे 2 सेंट लिखता हूं। मैं एक समाधान तैयार करता हूं जो वास्तव में बदलता है जो क्षणिक के समाधान के समान ही बदलता है।

मेरे ChangesTable होगा आसान हो:

DateTime | WhoChanged | TableName | Action | ID |FieldName | OldValue

1) जब एक पूरी पंक्ति मुख्य तालिका में बदल गया है, प्रविष्टियों की बहुत सारी इस तालिका में जाना जाएगा, लेकिन यह बहुत संभावना नहीं है, इसलिए नहीं एक बड़ी समस्या (लोग आमतौर पर केवल एक चीज बदल रहे हैं) 2) ओल्डव्यू (और यदि आप चाहते हैं तो न्यूवैल्यू) कुछ प्रकार का महाकाव्य "किसी प्रकार" होना चाहिए क्योंकि यह कोई डेटा हो सकता है, रॉ प्रकारों के साथ ऐसा करने का एक तरीका हो सकता है या बस कन्वर्ट करने के लिए JSON तारों का उपयोग कर।

न्यूनतम डेटा उपयोग, आपको जो कुछ भी चाहिए उसे स्टोर करता है और एक ही समय में सभी तालिकाओं के लिए उपयोग किया जा सकता है। मैं अभी इस पर खुद का शोध कर रहा हूं, लेकिन यह जिस तरह से मैं जा रहा हूं।

बनाने और हटाने के लिए, बस पंक्ति आईडी, कोई फ़ील्ड आवश्यक नहीं है। मुख्य तालिका (सक्रिय?) पर एक झंडा हटाने पर अच्छा होगा।

1

बिन लॉग फ़ाइलों का उपयोग क्यों न करें? यदि प्रतिकृति MySQL सर्वर पर सेट है, और binlog फ़ाइल प्रारूप ROW पर सेट है, तो सभी परिवर्तनों को कैद किया जा सकता है।

नोप्ले नामक एक अच्छी पायथन लाइब्रेरी का उपयोग किया जा सकता है। अधिक जानकारी here

+0

बिनलॉग का उपयोग तब भी किया जा सकता है जब आपके पास प्रतिकृति की आवश्यकता न हो। बिनलॉग में कई फायदेमंद उपयोग के मामले हैं। प्रतिकृति शायद सबसे आम उपयोग का मामला है, लेकिन यहां बताया गया है कि बैकअप और ऑडिट इतिहास के लिए इसे भी लीवरेज किया जा सकता है। – webaholik

-1

MSSQL2017 और उपयोग डाटा कैप्चर या ट्रैकिंग बदलें करने के लिए अद्यतन

https://docs.microsoft.com/en-us/sql/relational-databases/track-changes/track-data-changes-sql-server

की
+0

यह एक MySQL विशिष्ट प्रश्न है। MySQL में परिवर्तन ट्रैकिंग से निपटने के कई तरीके हैं। – webaholik