डेटाबेस एक "पूर्वावलोकन मोड" के साथ संग्रहीत प्रक्रिया


15

डेटाबेस एप्लिकेशन में मेरे द्वारा काम किया जाने वाला एक सामान्य पैटर्न एक रिपोर्ट या उपयोगिता के लिए एक संग्रहीत कार्यविधि बनाने की आवश्यकता है जिसमें "पूर्वावलोकन मोड" है। जब ऐसी प्रक्रिया अपडेट करती है, तो यह पैरामीटर इंगित करता है कि कार्रवाई के परिणाम वापस आ जाना चाहिए, लेकिन प्रक्रिया वास्तव में डेटाबेस को अपडेट नहीं करना चाहिए।

इसे पूरा करने का एक तरीका केवल ifपैरामीटर के लिए एक बयान लिखना है , और दो पूर्ण कोड ब्लॉक हैं; जिनमें से एक अपडेट करता है और डेटा लौटाता है और दूसरा सिर्फ डेटा लौटाता है। लेकिन कोड के दोहराव और अपेक्षाकृत कम आत्मविश्वास के कारण यह अवांछनीय है कि पूर्वावलोकन डेटा वास्तव में एक अपडेट के साथ क्या होगा, इसका सटीक प्रतिबिंब है।

निम्नलिखित उदाहरण लाइव अपडेट मोड के रूप में पूर्वावलोकन मोड के लिए कोड के सिर्फ एक ब्लॉक का उपयोग करने के लिए लेनदेन की बचत और चर (जो कि टेम्‍प टेबल के विपरीत लेनदेन से प्रभावित नहीं हैं) का लाभ उठाने का प्रयास करता है।

नोट: लेन-देन रोलबैक एक विकल्प नहीं है क्योंकि यह प्रक्रिया कॉल खुद को लेनदेन में निहित हो सकती है। यह SQL Server 2012 पर परीक्षण किया गया है।

CREATE TABLE dbo.user_table (a int);
GO

CREATE PROCEDURE [dbo].[PREVIEW_EXAMPLE] (
  @preview char(1) = 'Y'
) AS

CREATE TABLE #dataset_to_return (a int);

BEGIN TRANSACTION; -- preview mode required infrastructure
  DECLARE @output_to_return TABLE (a int);
  SAVE TRANSACTION savepoint;

  -- do stuff here
  INSERT INTO dbo.user_table (a)
    OUTPUT inserted.a INTO @output_to_return (a)
    VALUES (42);

  -- catch preview mode
  IF @preview = 'Y'
    ROLLBACK TRANSACTION savepoint;

  -- save output to temp table if used for return data
  INSERT INTO #dataset_to_return (a)
  SELECT a FROM @output_to_return;
COMMIT TRANSACTION;

SELECT a AS proc_return_data FROM #dataset_to_return;
RETURN 0;
GO

-- Examples
EXEC dbo.PREVIEW_EXAMPLE @preview = 'Y';
SELECT a AS user_table_after_preview_mode FROM user_table;

EXEC dbo.PREVIEW_EXAMPLE @preview = 'N';
SELECT a AS user_table_after_live_mode FROM user_table;

-- Cleanup
DROP TABLE dbo.user_table;
DROP PROCEDURE dbo.PREVIEW_EXAMPLE;
GO

मैं इस कोड और डिजाइन पैटर्न पर प्रतिक्रिया की तलाश कर रहा हूं, और / या यदि एक ही समस्या के अन्य समाधान विभिन्न स्वरूपों में मौजूद हैं।

जवाबों:


12

इस दृष्टिकोण के कई दोष हैं:

  1. शब्द "पूर्वावलोकन" ज्यादातर मामलों में काफी भ्रामक हो सकता है, यह इस बात पर निर्भर करता है कि डेटा किसके द्वारा संचालित किया जा रहा है (और वह ऑपरेशन से ऑपरेशन में बदलता है)। यह सुनिश्चित करने के लिए कि वर्तमान डेटा जिस पर संचालित किया जा रहा है, वह उसी स्थिति में होगा जब "पूर्वावलोकन" डेटा एकत्र किया जाता है और जब उपयोगकर्ता 15 मिनट बाद वापस आता है - कुछ कॉफी हथियाने के बाद, धुएं के लिए बाहर कदम रखते हुए, चलना ब्लॉक के आसपास, वापस आकर और ईबे पर कुछ चेक करना - और यह महसूस करता है कि उन्होंने वास्तव में ऑपरेशन करने के लिए "ओके" बटन पर क्लिक नहीं किया है और इसलिए बटन पर क्लिक करता है?

    क्या आपके पास पूर्वावलोकन उत्पन्न होने के बाद ऑपरेशन के साथ आगे बढ़ने की समय-सीमा है? या संभवतः यह निर्धारित करने का एक तरीका है कि डेटा उसी स्थिति में है जिस समय यह प्रारंभिक SELECTसमय में था?

  2. यह एक मामूली बात है क्योंकि उदाहरण कोड जल्दबाजी में किया जा सकता था और एक सच्चे उपयोग-मामले का प्रतिनिधित्व नहीं करता था, लेकिन एक INSERTऑपरेशन के लिए "पूर्वावलोकन" क्यों होगा ? जब किसी चीज़ के माध्यम से कई पंक्तियाँ सम्मिलित करते समय यह समझ में आता है INSERT...SELECTऔर इसमें पंक्तियों की एक चर संख्या सम्मिलित हो सकती है, लेकिन यह एक सिंगलटन ऑपरेशन के लिए बहुत मायने नहीं रखता है।

  3. इसकी वजह से यह अवांछनीय है ... विश्वास का अपेक्षाकृत कम स्तर कि पूर्वावलोकन डेटा वास्तव में एक अद्यतन के साथ क्या होगा का एक सटीक प्रतिबिंब है।

    वास्तव में यह "आत्मविश्वास की कम डिग्री" कहाँ से आती है? जब एक से SELECTअधिक तालिकाओं के लिए शो के मुकाबले पंक्तियों की एक अलग संख्या को अपडेट करना संभव होता है, तो परिणामी सेट में पंक्तियों का दोहराव होता है, यहाँ एक मुद्दा नहीं होना चाहिए। ऐसी कोई भी पंक्तियाँ जिनसे प्रभावित होना चाहिए, UPDATEवे अपने आप ही चयन करने योग्य हैं। अगर कोई मिसमैच है तो आप गलत तरीके से क्वेरी कर रहे हैं।

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

  4. पूर्णता के लिए (भले ही अन्य उत्तरों ने यह उल्लेख किया हो), आप TRY...CATCHनिर्माण का उपयोग नहीं कर रहे हैं, इसलिए इन कॉलों को नेस्ट करते समय आसानी से मुद्दों में चला सकते हैं (भले ही सेव पॉइंट्स का उपयोग न करें, और लेनदेन का उपयोग न करने पर भी)। कृपया निम्नलिखित प्रश्न के लिए मेरा उत्तर देखें, यहां DBA.SE पर, एक ऐसे टेम्पलेट के लिए, जो नेस्टेड संग्रहीत कार्यविधि में लेनदेन को संभालता है:

    क्या हमें C # कोड में लेन-देन के साथ-साथ संग्रहीत कार्यविधि को भी संभालने की आवश्यकता है

  5. EVEN यदि ऊपर दिए गए मुद्दों का लेखा-जोखा किया गया है, तो अभी भी एक महत्वपूर्ण दोष है: समय की छोटी अवधि के लिए ऑपरेशन का प्रदर्शन किया जा रहा है (यानी इससे पहले ROLLBACK), कोई भी गंदा-पढ़ने वाला प्रश्न (उपयोग WITH (NOLOCK)कर रहा है SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED) या डेटा को हड़प सकता है एक पल बाद नहीं है। जबकि गंदे-पढ़ने वाले प्रश्नों का उपयोग करने वाले किसी को भी पहले से ही इसके बारे में पता होना चाहिए और उस संभावना को स्वीकार कर लिया है, इस तरह के संचालन से डेटा विसंगतियों को शुरू करने की संभावना बहुत बढ़ जाती है जो कि डिबग करना बहुत मुश्किल है (अर्थ: कितना समय आप कोशिश करना चाहते हैं? एक ऐसी समस्या का पता लगाएं जिसका कोई प्रत्यक्ष कारण नहीं है?)।

  6. इस तरह का एक पैटर्न भी अधिक तालों को निकालकर, और अधिक लेन-देन लॉग गतिविधि उत्पन्न करके दोनों को अवरुद्ध करके प्रणाली के प्रदर्शन को नीचा दिखाता है। (मैं अब देख रहा हूं कि @MartinSmith ने प्रश्न पर एक टिप्पणी में इन 2 मुद्दों का उल्लेख किया है।)

    इसके अतिरिक्त, यदि वहाँ संशोधित किए जा रहे तालिकाओं पर ट्रिगर हैं, तो यह काफी अतिरिक्त प्रसंस्करण (CPU और भौतिक / तार्किक रीड) हो सकता है जो अनावश्यक है। ट्रिगर भी गंदे रीड्स के परिणामस्वरूप डेटा विसंगतियों की संभावना को बढ़ाएंगे।

  7. सीधे ऊपर बताए गए बिंदु से संबंधित - बढ़े हुए ताले - लेन-देन के उपयोग से गतिरोध में चलने की संभावना बढ़ जाती है, खासकर अगर ट्रिगर शामिल हो।

  8. एक कम गंभीर समस्या जो केवल INSERTसंचालन के कम-संभावित परिदृश्य से संबंधित होनी चाहिए : "पूर्वावलोकन" डेटा वैसा ही नहीं हो सकता है जैसा कि DEFAULTबाधाओं ( Sequences/ NEWID()/ NEWSEQUENTIALID()) और द्वारा निर्धारित स्तंभ मानों के संबंध में डाला गया है IDENTITY

  9. अस्थायी तालिका में तालिका परिवर्तनीय की सामग्री को लिखने के लिए अतिरिक्त ओवरहेड की आवश्यकता नहीं है। ROLLBACKतालिका चर में डेटा प्रभाव पड़ेगा (और इसी कारण आप ने कहा कि आप पहली जगह में टेबल चर उपयोग कर रहे थे), तो यह बस के लिए और अधिक समझ बनाने जाएगा SELECT FROM @output_to_return;अंत में, और फिर भी अस्थायी बनाने के लिए परेशान नहीं करते टेबल।

  10. बस इस मामले में सेव पॉइंट्स की बारीकियों का पता नहीं चलता है (उदाहरण कोड से बताना मुश्किल है क्योंकि यह केवल एक एकल प्रक्रिया दिखाती है): आपको यूनीक सेव पॉइंट पॉइंट नामों का उपयोग करने की आवश्यकता है ताकि ROLLBACK {save_point_name}ऑपरेशन उसी तरह से व्यवहार करे जैसा आप उससे उम्मीद कर रहे हैं। यदि आप नामों का फिर से उपयोग करते हैं, तो एक ROLLBACK उस नाम के सबसे हाल के सहेजें बिंदु को रोल-बैक करेगा, जो शायद उसी घोंसले के स्तर पर नहीं हो सकता है जहां ROLLBACKसे बुलाया जा रहा है। कार्रवाई में इस व्यवहार को देखने के लिए कृपया निम्नलिखित उत्तर में पहला उदाहरण कोड ब्लॉक देखें: संग्रहीत कार्यविधि में लेन-देन

यह क्या है:

  • "पूर्वावलोकन" करने से उपयोगकर्ता-सामना करने वाले कार्यों के लिए बहुत अधिक समझ में नहीं आता है। मैं रखरखाव कार्यों के लिए अक्सर ऐसा करता हूं ताकि मैं देख सकूं कि यदि मैं ऑपरेशन के साथ आगे बढ़ता हूं तो क्या हटाया जाएगा / कचरा एकत्र किया जाएगा। मैं एक वैकल्पिक पैरामीटर को जोड़ता हूं @TestModeऔर एक IFबयान करता हूं जो या तो SELECTजब @TestMode = 1यह करता है तो यह करता है DELETE। मैं कभी-कभी @TestModeएप्लिकेशन द्वारा बुलाए गए संग्रहीत कार्यविधियों के लिए पैरामीटर जोड़ता हूं ताकि मैं (और अन्य) डेटा की स्थिति को प्रभावित किए बिना सरल परीक्षण कर सकें, लेकिन इस पैरामीटर का उपयोग कभी भी एप्लिकेशन द्वारा नहीं किया जाता है।

  • बस इस मामले में "मुद्दों" के शीर्ष खंड से स्पष्ट नहीं था:

    यदि आपको डीएमएल स्टेटमेंट को निष्पादित करने के लिए क्या प्रभावित होना चाहिए, यह देखने के लिए आपको "पूर्वावलोकन" / "टेस्ट" मोड की आवश्यकता है / चाहते हैं, तो इसेBEGIN TRAN...ROLLBACK पूरा करने के लिए लेन-देन (यानी पैटर्न) का उपयोग न करें । यह एक ऐसा पैटर्न है, जो वास्तव में, केवल एकल-उपयोगकर्ता प्रणाली पर काम करता है, और उस स्थिति में एक अच्छा विचार भी नहीं है।

  • IFकथन की दो शाखाओं के बीच क्वेरी के थोक को दोहराने से दोनों को अपडेट करने की आवश्यकता की एक संभावित समस्या पेश होती है, हर बार बदलाव करने के लिए। हालाँकि, दो प्रश्नों के बीच अंतर आमतौर पर कोड की समीक्षा में पकड़ना और ठीक करना आसान होता है। दूसरी ओर, राज्य के अंतर और गंदे पढ़ी जाने जैसी समस्याओं को ढूंढना और ठीक करना बहुत कठिन है। और सिस्टम प्रदर्शन में कमी की समस्या को ठीक करना असंभव है। हमें यह पहचानने और स्वीकार करने की आवश्यकता है कि एसक्यूएल एक ऑब्जेक्ट-ओरिएंटेड भाषा नहीं है, और डुप्लिकेटेड कोड को कम करना / कम करना SQL का डिज़ाइन-लक्ष्य नहीं था, जैसे कि यह कई अन्य भाषाओं के साथ था।

    यदि क्वेरी काफी लंबी / जटिल है, तो आप इसे इनलाइन टेबल-वैल्यूएड फ़ंक्शन में एनकैप कर सकते हैं। फिर आप SELECT * FROM dbo.MyTVF(params);"पूर्वावलोकन" मोड के लिए एक सरल कर सकते हैं , और "इसे करें" मोड के लिए कुंजी मूल्य पर जाएं। उदाहरण के लिए:

    UPDATE tab
    SET    tab.Col2 = tvf.ColB
           ...
    FROM   dbo.Table tab
    INNER JOIN dbo.MyTVF(params) tvf
            ON tvf.ColA = tab.Col1;
  • यदि यह एक रिपोर्ट परिदृश्य है जैसा कि आपने उल्लेख किया है कि यह हो सकता है, तो प्रारंभिक रिपोर्ट चलाना "पूर्वावलोकन" है। यदि कोई व्यक्ति रिपोर्ट (शायद एक स्थिति) पर कुछ देखना चाहता है, तो उसे अतिरिक्त पूर्वावलोकन की आवश्यकता नहीं है क्योंकि वर्तमान में प्रदर्शित डेटा को बदलने की उम्मीद है।

    यदि ऑपरेशन को निश्चित% या व्यावसायिक नियम द्वारा बोली राशि को बदलना है, तो उसे प्रस्तुति परत (जावास्क्रिप्ट?) में संभाला जा सकता है।

  • यदि आपको वास्तव में एंड-यूज़र-फ़ेसिंग ऑपरेशन के लिए "पूर्वावलोकन" करने की आवश्यकता है, तो आपको पहले डेटा की स्थिति पर कब्जा करने की आवश्यकता है (शायद UPDATEसंचालन के लिए निर्धारित परिणाम में सभी फ़ील्ड का एक हैश या इसके लिए महत्वपूर्ण मान DELETE- संचालन), और फिर, आपरेशन प्रदर्शन से पहले, वर्तमान जानकारी के साथ कब्जा कर लिया राज्य जानकारी की तुलना किसी लेन-देन के भीतर एक कर HOLDमेज पर ताला ताकि इस तुलना करने के बाद कुछ भी नहीं परिवर्तन - और अगर कोई अंतर कर रहे हैं, एक फेंक त्रुटि या के ROLLBACKबजाय आगे बढ़ने के साथ UPDATEया करते हैं DELETE

    के लिए मतभेदों का पता लगाने के लिए UPDATEसंचालन, प्रासंगिक क्षेत्रों पर एक हैश कंप्यूटिंग के लिए एक विकल्प प्रकार का एक स्तंभ जोड़ने के लिए किया जाएगा ROWVERSIONROWVERSIONडेटाटाइप का मान स्वचालित रूप से हर बार उस पंक्ति में परिवर्तन होने पर बदलता है। यदि आपके पास ऐसा कोई कॉलम था, तो आप SELECTइसे अन्य "पूर्वावलोकन" डेटा के साथ ले लेंगे , और फिर इसे "सुनिश्चित करें, आगे बढ़ें और अपडेट करें" कुंजी मान (एस) और मान के साथ कदम रखें। बदलने के लिए। तो आप उन तुलना होगा ROWVERSIONमूल्यों पारित कर दिया-में "पूर्वावलोकन" से वर्तमान मूल्यों (प्रत्येक कुंजी प्रति) के साथ है, और केवल के साथ आगे बढ़ना UPDATEहै, तो सभीके मूल्यों का मिलान हुआ। यहाँ लाभ यह है कि आपको एक हैश की गणना करने की आवश्यकता नहीं है, जिसमें क्षमता है, भले ही संभावना न हो, झूठे-नकारात्मक के लिए, और प्रत्येक बार जब आप कुछ समय लेते हैं और कुछ समय लेते हैं SELECT। दूसरी ओर, ROWVERSIONमूल्य केवल बदले जाने पर स्वचालित रूप से बढ़ जाता है, इसलिए आपको कभी भी चिंता करने की आवश्यकता नहीं है। हालांकि, ROWVERSIONप्रकार 8 बाइट्स है, जो कई तालिकाओं और / या कई पंक्तियों के साथ काम करते समय जोड़ सकते हैं।

    UPDATEसंचालन से संबंधित असंगत स्थिति का पता लगाने के लिए इन दो तरीकों में से प्रत्येक के लिए पेशेवरों और विपक्ष हैं , इसलिए आपको यह निर्धारित करने की आवश्यकता होगी कि आपके सिस्टम के लिए "कॉन" की तुलना में किस विधि में अधिक "समर्थक" है। लेकिन या तो मामले में, आप पूर्वावलोकन बनाने और एंड-यूज़र की अपेक्षाओं के बाहर व्यवहार करने से ऑपरेशन करने में देरी से बच सकते हैं।

  • यदि आप एंड-यूज़र-फेसिंग "प्रीव्यू" मोड कर रहे हैं, तो चयन-समय पर रिकॉर्ड्स की स्थिति को कैप्चर करने के अलावा , साथ-साथ गुजरना और संशोधन-समय पर जाँच करना, एक के DATETIMEलिए शामिल करना SelectTimeऔर इसके माध्यम से GETDATE()या कुछ समान करना। इसे ऐप लेयर के साथ पास करें ताकि इसे स्टोर की गई प्रक्रिया में वापस भेजा जा सके (ज्यादातर सिंगल इनपुट पैरामीटर के रूप में होने की संभावना है) ताकि इसे स्टोर की गई प्रक्रिया में जांचा जा सके। तब आप यह निर्धारित कर सकते हैं कि यदि ऑपरेशन "पूर्वावलोकन" मोड नहीं है, तो वर्तमान मूल्य से पहले मूल्य की एक्स मिनट से अधिक नहीं@SelectTime होनी चाहिए । शायद २ मिनट? 5 मिनट? सबसे अधिक संभावना 10 मिनट से अधिक नहीं। उस थ्रेशोल्ड में MINUTES में त्रुटि होने पर उसे फेंक दें ।GETDATE()DATEDIFF


4

सबसे सरल दृष्टिकोण अक्सर सबसे अच्छा होता है और मेरे पास एसक्यूएल में कोड डुप्लिकेट के साथ वास्तव में ऐसा कोई मुद्दा नहीं है, विशेष रूप से एक ही मॉड्यूल में नहीं। आखिर दोनों प्रश्न अलग-अलग काम कर रहे हैं। तो क्यों न 'रूट 1' लें या इसे सिंपल रखें और स्टोर किए गए खरीद में बस दो सेक्शन हैं, एक आपको जो काम करने की जरूरत है उसका अनुकरण करने के लिए और एक इसे करने के लिए, जैसे कुछ इस तरह:

CREATE TABLE dbo.user_table ( rowId INT IDENTITY PRIMARY KEY, a INT NOT NULL, someGuid UNIQUEIDENTIFIER DEFAULT NEWID() );
GO
CREATE PROCEDURE [dbo].[PREVIEW_EXAMPLE2]

    @preview CHAR(1) = 'Y'

AS

    SET NOCOUNT ON

    --!!TODO add error handling

    IF @preview = 'Y'

        -- Simulate INSERT; could be more complex
        SELECT 
            ISNULL( ( SELECT MAX(rowId) FROM dbo.user_table ), 0 ) + 1 AS rowId,
            42 AS a,
            NEWID() AS someGuid

    ELSE

        -- Actually do the INSERT, return inserted values
        INSERT INTO dbo.user_table ( a )
        OUTPUT inserted.rowId, inserted.a, inserted.someGuid
        VALUES ( 42 )

    RETURN

GO

यह स्व-दस्तावेजीकरण होने का लाभ है (अर्थात, IF ... ELSEइसका अनुसरण करना आसान है), कम जटिलता (टेबल चर दृष्टिकोण IMO के साथ बचत बिंदु की तुलना में), इसलिए कम कीड़े (@Cody से महान स्थान) होने की संभावना है।

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

एक तरफ के रूप में, आपको एक प्राथमिक कुंजी सेट करने पर विचार करना चाहिए NULL/ NOT NULLसंपत्ति और अपने टेबल और टेबल चर सेट करना चाहिए ।

आपका मूल दृष्टिकोण थोड़ा अधिक जटिल लगता है, संभवतः गतिरोध के लिए अधिक प्रवण हो सकता है, क्योंकि INSERT/ UPDATE/ DELETEसंचालन को सादे से अधिक लॉकिंग स्तर की आवश्यकता होती है SELECTs

मुझे संदेह है कि आपकी वास्तविक दुनिया procs अधिक जटिल हैं, इसलिए यदि आपको लगता है कि उपरोक्त दृष्टिकोण उनके लिए काम नहीं करेगा, तो कुछ और उदाहरणों के साथ वापस पोस्ट करें।


3

मेरी चिंताएं इस प्रकार हैं।

  • ट्रांजेक्शन हैंडलिंग स्टार्टिंग / स्टार्ट कैच ब्लॉक में नेस्टेड होने के मानक पैटर्न का पालन नहीं करता है। यदि यह एक टेम्पलेट है, तो कुछ और चरणों के साथ संग्रहीत कार्यविधि में आप अभी भी संशोधित डेटा के साथ पूर्वावलोकन मोड में इस लेनदेन से बाहर निकल सकते हैं।

  • प्रारूप के बाद डेवलपर कार्य में वृद्धि होती है। यदि वे आंतरिक स्तंभों को बदलते हैं, तो उन्हें तालिका चर परिभाषा को संशोधित करने की भी आवश्यकता होती है, फिर अस्थायी तालिका परिभाषा को संशोधित करें, फिर अंत में सम्मिलित कॉलम को संशोधित करें। यह लोकप्रिय होने वाला नहीं है।

  • कुछ संग्रहीत कार्यविधियाँ डेटा के समान प्रारूप को हर बार वापस नहीं करती हैं; एक सामान्य उदाहरण के रूप में sp_WhoIsActive के बारे में सोचें।

मैंने इसे करने का बेहतर तरीका नहीं दिया है, लेकिन मुझे नहीं लगता कि आपके पास एक अच्छा पैटर्न है।

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