उत्तर देने से पहले, मैं पहले यह कह दूं कि मुझे नहीं लगता कि सभी तालिकाओं को एक ही तालिका में लॉग करना सबसे अच्छा है। यदि आपका डेटाबेस बढ़ता है तो आप लॉग टेबल पर गंभीर विवाद के साथ समाप्त हो सकते हैं। साथ ही, एक ही कॉलम में डालने के लिए आपके सभी डेटा को varchar या sql_variant में बदलना होगा, जिससे यह अधिक स्थान लेने के लिए मजबूर हो जाएगा। मुझे यह भी लगता है कि प्रत्येक अपडेट किए गए कॉलम को एक अलग पंक्ति में लॉगिंग करना (कॉलम जो अपडेट नहीं किया गया है) को छोड़ना इसे बहुत बनाने जा रहा है आपके लिए पूछताछ करना कठिन है। क्या आप जानते हैं कि प्रत्येक पंक्ति के परिवर्तनों के बारे में एक समग्र और समझदार दृष्टिकोण प्राप्त करने के लिए उस सभी डेटा को एक साथ कैसे खींचना है, कब और किसके द्वारा? प्रति टेबल एक लॉग टेबल होना, मेरी राय में, बहुत आसान होने वाला है। तब आपको वह समस्या नहीं होगी जो आप इसे काम करने की कोशिश में अनुभव कर रहे हैं।
साथ ही, क्या आप SQL Server 2008 के बारे में जानते हैं डेटा कैप्चर बदलें ? यदि आप SQL सर्वर के एंटरप्राइज़ या डेवलपर संस्करण का उपयोग कर रहे हैं, तो इसके बजाय इसका उपयोग करें!
उस मुद्दे के अलावा, आप तार्किक UNPIVOT (अपने स्वयं के संस्करण का प्रदर्शन) के साथ वह कर सकते हैं जो आप चाहते हैं। आप वास्तव में मूल SQL 2005 UNPIVOT का उपयोग नहीं कर सकते क्योंकि आपके पास दो लक्ष्य स्तंभ हैं, एक नहीं। यहाँ UNPIVOT करने के लिए CROSS APPLY का उपयोग करके SQL Server 2005 और बाद के संस्करण के लिए एक उदाहरण दिया गया है:
INSERT INTO dbo.LOG (Id_Table, Table_Key_Value, Id_Value, Old_Value, New_Value)
SELECT 12345, I.Id, X.Id_Value, X.Old_Value, X.New_Value
FROM
INSERTED I
INNER JOIN DELETED D ON I.ID = D.ID
CROSS APPLY (
SELECT 4556645, D.Name, I.Name
UNION ALL SELECT 544589, D.Surname, I.Surname
) X (Id_Value, Old_Value, New_Value)
WHERE
X.Old_Value <> X.New_Value
यहाँ SQL 2000 या अन्य DBMSes के लिए एक अधिक सामान्य विधि है (सैद्धांतिक रूप से Oracle, MySQL, आदि में काम करना चाहिए - Oracle के लिए FROM DUAL
जोड़ें) व्युत्पन्न तालिका में प्रत्येक चयन के लिए):
INSERT INTO dbo.LOG (Id_Table, Table_Key_Value, Id_Value, Old_Value, New_Value)
SELECT *
FROM (
SELECT
12345,
I.Id,
X.Id_Value,
CASE X.Id_Value
WHEN 4556645 THEN D.Name
WHEN 544589 THEN D.Surname
END Old_Value,
CASE X.Id_Value
WHEN 4556645 THEN I.Name
WHEN 544589 THEN I.Surname
END New_Value
FROM
INSERTED I
INNER JOIN DELETED D ON I.ID = D.ID
CROSS JOIN (
SELECT 4556645
UNION ALL SELECT 544589
) X (Id_Value)
) Y
WHERE
Y.Old_Value <> Y.New_Value
SQL सर्वर 2005 और बाद के संस्करण में मूल UNPIVOT कमांड है, हालांकि सामान्य तौर पर, जब UNPIVOT काम करेगा, तब भी मुझे इसके बजाय CROSS APPLY का उपयोग करना पसंद है क्योंकि मैं जो चाहता हूं उसे करने के लिए अधिक लचीलापन है। विशेष रूप से, मूल UNPIVOT कमांड यहां काम करने योग्य नहीं है क्योंकि UNPIVOT केवल एक गंतव्य कॉलम को लक्षित कर सकता है, लेकिन आपको दो (Old_Value, New_Value) की आवश्यकता है। दो स्तंभों को एक ही मान में जोड़ना (और बाद में अलग करना) अच्छा नहीं है; बाद में PIVOT के लिए एक अर्थहीन पंक्ति सहसंबंधक मान बनाना अच्छा नहीं है, और मैं ऐसा करने का दूसरा तरीका नहीं सोच सकता जो उन दोनों पर भिन्नता नहीं है। आपके द्वारा वर्णित सटीक लॉग तालिका संरचना से मेल खाने के लिए क्रॉस लागू समाधान वास्तव में आपके लिए सबसे अच्छा होगा।
यहां मेरे प्रश्नों की तुलना में, आपकी विधि #1 अच्छा प्रदर्शन नहीं करेगी (लगभग {स्तंभों की संख्या}:1 खराब प्रदर्शन के अनुपात में)। आपकी विधि #2 एक अच्छा विचार है, लेकिन फिर भी उप-इष्टतम है क्योंकि यूडीएफ को कॉल करना एक बड़ा ओवरहेड है, साथ ही आपको प्रत्येक पंक्ति (कंपकंपी) पर लूप करना होगा।