DAO के साथ Microsoft SQL संग्रहीत कार्यविधि के लिए बड़े पैरामीटर का उपयोग करना
जैसा कि आप में से बहुत से लोग पहले से ही जानते हैं, SQL सर्वर टीम ने SQL सर्वर डेटाबेस इंजन के लिए OLEDB के बहिष्करण की घोषणा की है (पढ़ें:हम ADO का उपयोग नहीं कर सकते क्योंकि ADO OLEDB का उपयोग करता है)। इसके अतिरिक्त, SQL Azure आधिकारिक तौर पर ADO का समर्थन नहीं करता है, हालांकि कोई अभी भी SQL सर्वर मूल क्लाइंट का उपयोग करके इससे दूर हो सकता है। हालाँकि, नया 13.1 ODBC ड्राइवर कई सुविधाओं के साथ आता है जो SQL सर्वर नेटिव क्लाइंट में उपलब्ध नहीं होंगे, और और भी आ सकते हैं।
निचली पंक्ति:हमें शुद्ध डीएओ के साथ काम करने की ज़रूरत है। एक्सेस/ओडीबीसी या एक्सेस/एसक्यूएल सर्वर… के विषय पर पहले से ही कई उपयोगकर्ता वॉयस आइटम स्पर्श कर रहे हैं, उदाहरण के लिए:
डेटा कनेक्टर SQL सर्वर
SQL सर्वर के साथ बेहतर एकीकरण
SQL Azure के साथ बेहतर एकीकरण
कृपया एक्सेस को अधिक डेटा प्रकारों को संभालने में सक्षम बनाएं जैसा कि आमतौर पर सर्वर डेटाबेस में उपयोग किया जाता है
एक्सेस को बेहतर बनाएं ओडीबीसी क्लाइंट
(यदि आपने मतदान नहीं किया है या access.uservoice.com पर नहीं गए हैं, तो वहां जाएं और वोट करें यदि आप चाहते हैं कि एक्सेस टीम आपकी पसंदीदा सुविधा को लागू करे)
लेकिन भले ही माइक्रोसॉफ्ट अगले संस्करण में डीएओ को बढ़ाए, फिर भी हमें अपने ग्राहक के मौजूदा अनुप्रयोगों से निपटना होगा। हमने OLEDB प्रदाता (MSDASQL) पर ODBC का उपयोग करने पर विचार किया, लेकिन हमने महसूस किया कि यह एक मरते हुए घोड़े पर एक टट्टू को घुमाने जैसा था। यह काम कर सकता है लेकिन यह कुछ ही देर में मर सकता है।
अधिकांश भाग के लिए, एक पासथ्रू क्वेरी वह करेगी जो हमें करने की आवश्यकता है और डीएओ पास-थ्रू क्वेरी का उपयोग करके एडीओ की कार्यक्षमता की नकल करने के लिए एक फ़ंक्शन को एक साथ फेंकना आसान है। लेकिन एक महत्वपूर्ण अंतर है जिसे आसानी से दूर नहीं किया जा सकता है - संग्रहित प्रक्रियाओं के लिए बड़े पैरामीटर। जैसा कि मैंने पहले लिखा था, हम कभी-कभी एक्सएमएल पैरामीटर का उपयोग बड़ी मात्रा में डेटा पास करने के तरीके के रूप में करते हैं, जो एक्सेस वास्तव में सभी डेटा को एक-एक करके डालने से कहीं अधिक तेज़ है। हालाँकि, SQL कमांड के लिए DAO क्वेरी लगभग 64K वर्णों तक सीमित है और व्यवहार में इससे भी कम हो सकती है। हमें पैरामीटर पास करने का एक तरीका चाहिए जो 64K वर्णों से बड़ा हो सकता है, इसलिए हमें एक समाधान के बारे में सोचना पड़ा।
tblExecuteStoredProcedure तालिका दर्ज करें
हमने जो तरीका चुना वह एक टेबल का उपयोग करना था क्योंकि जब हम नए ओडीबीसी ड्राइवर या एसक्यूएल सर्वर नेटिव क्लाइंट का उपयोग करते हैं, तो डीएओ आसानी से टेबल में सीधे सम्मिलित करके बड़ी मात्रा में टेक्स्ट (उर्फ मेमो) को संभालने में सक्षम होता है। इसलिए, एक बड़े एक्सएमएल पैरामीटर को निष्पादित करने के लिए, हम निष्पादित करने की प्रक्रिया और उसके पैरामीटर को तालिका में लिखेंगे, फिर ट्रिगर को इसे लेने दें। यहाँ तालिका निर्माण स्क्रिप्ट है:
CREATE TABLE dbo.tblExecuteStoredProcedure (
ExecuteID int NOT NULL IDENTITY
CONSTRAINT PK_tblExecuteStoredProcedure PRIMARY KEY CLUSTERED,
ProcedureSchema sysname NOT NULL
CONSTRAINT DF_tblExecuteStoredProcedure DEFAULT 'dbo',
ProcedureName sysname NOT NULL,
Parameter1 nvarchar(MAX) NULL,
Parameter2 nvarchar(MAX) NULL,
Parameter3 nvarchar(MAX) NULL,
Parameter4 nvarchar(MAX) NULL,
Parameter5 nvarchar(MAX) NULL,
Parameter6 nvarchar(MAX) NULL,
Parameter7 nvarchar(MAX) NULL,
Parameter8 nvarchar(MAX) NULL,
Parameter9 nvarchar(MAX) NULL,
Parameter10 nvarchar(MAX) NULL,
RV rowversion NOT NULL
);
बेशक, हम वास्तव में इसे वास्तविक तालिका की तरह उपयोग करने का इरादा नहीं रखते हैं। हम मनमाने ढंग से 10 पैरामीटर भी सेट करते हैं, भले ही एक संग्रहीत प्रक्रिया में कई और अधिक हो सकते हैं। हालांकि, हमारे अनुभव में, 10 से अधिक होना काफी दुर्लभ है, खासकर जब हम एक्सएमएल पैरामीटर के साथ काम कर रहे हों। अपने आप में, तालिका बहुत उपयोगी नहीं होगी। हमें एक ट्रिगर चाहिए:
CREATE TRIGGER dbo.tblExecuteStoredProcedureAfterInsert
ON dbo.tblExecuteStoredProcedure AFTER INSERT AS
BEGIN
--Throw if multiple inserts were performed
IF 1 < (
SELECT COUNT(*)
FROM inserted
)
BEGIN
ROLLBACK TRANSACTION;
THROW 50000, N'Cannot perform multiple-row inserts on the table `tblExecuteStoredProcedure`.', 1;
RETURN;
END;
-केवल एक रिकॉर्ड को प्रोसेस करें जो अंतिम डाला जाना चाहिए
DECLARE @ProcedureSchema sysname,
@ProcedureName sysname,
@FullyQualifiedProcedureName nvarchar(MAX),
@Parameter1 nvarchar(MAX),
@Parameter2 nvarchar(MAX),
@Parameter3 nvarchar(MAX),
@Parameter4 nvarchar(MAX),
@Parameter5 nvarchar(MAX),
@Parameter6 nvarchar(MAX),
@Parameter7 nvarchar(MAX),
@Parameter8 nvarchar(MAX),
@Parameter9 nvarchar(MAX),
@Parameter10 nvarchar(MAX),
@Params nvarchar(MAX),
@ParamCount int,
@ParamList nvarchar(MAX),
@Sql nvarchar(MAX);
चुनें
@ProcedureSchema =p.ProcedureSchema,
@ProcedureName =p.ProcedureName,
@FullyQualifiedProcedureName =CONCAT(QUOTENAME(p.ProcedureSchema), N'.', QUOTENAME(p.ProcedureName) ),
@Parameter1 =p.Parameter1,
@Parameter2 =p.Parameter2
AS p
से डाला गया जहां p.RV =(
MAX(x. RV)
X के रूप में सम्मिलित किए गए से
);
SET @Params =STUFF((
SELECT
CONCAT(
N',',
p.name,
N' =',
p. नाम
)
sys.parameters से p
इनर जॉइन sys.type AS t
p.user_type_id =t.user_type_id
जहां p.object_id =OBJECT_ID( @FullyQualifiedProcedureName)
XML PATH(N")
), 1, 1, N");
SET @ParamList =STUFF((
SELECT
CONCAT(
N',',
p.name,
N' ',
t.name ,
मामला
जब t.name N'%char%' या t.name LIKE '%binary%'
तब CONCAT(N'(', IIF(p.max_length =- 1, N'MAX', CAST(p.max_length AS nvarchar(11))), N')')
जब t.name ='दशमलव' या t.name ='संख्यात्मक'
तब CONCAT(N'(', p.precision, N',', p.scale, N')')
ELSE N”
END
)
FROM sys.parameters जैसे p
इनर जॉइन sys.types as t
ON p.user_type_id =t.user_type_id
जहां p.object_id =OBJECT_ID(@FullyQualifiedProcedureName)
XML PATH(N") के लिए
), 1, 1, एन");
SET @ParamCount =(
सेलेक्ट COUNT(*)
sys.parameters से p
जहां p.object_id =OBJECT_ID(@FullyQualifiedProcedureName)
);
SET @ParamList +=((
SELECT
CONCAT(N',', p.ParameterName, N' nvarchar(1)')
FROM (VALUES
(1, N) '@ पैरामीटर1′),
(2, N'@Parameter2′),
(3, N'@Parameter3′),
(4, N'@Parameter4′),
(5, N'@Parameter5′),
(6, N'@Parameter6′),
(7, N'@Parameter7′),
(8, N'@ Parameter8′),
(9, N'@Parameter9′),
(10, N'@Parameter10′)
) AS p(ParameterID, ParameterName)
WHERE p. ParameterID> @ParamCount
XML PATH(N”)
) के लिए);
SET @Sql =CONCAT (N'EXEC ', @FullyQualifiedProcedureName, N' ', @Params, N';');
-किसी भी परिणाम सेट को ट्रिगर से लौटाए जाने से रोकें (जिसे बहिष्कृत किया गया है)
-यदि कोई संग्रहीत प्रक्रिया कोई लौटाती है, तो ट्रिगर एक त्रुटि में समाप्त हो जाएगा
EXECUTE sys.sp_executesql @Sql, @ParamList, @ पैरामीटर1, @पैरामीटर2,@पैरामीटर3,@पैरामीटर4,@पैरामीटर5,@पैरामीटर6,@पैरामीटर7,@पैरामीटर8,@पैरामीटर9,@पैरामीटर10
परिणाम सेट के साथ कोई नहीं;
dbo.tblExecuteStoredProcedure
से हटाएं जहां मौजूद है (
सेलेक्ट करें
इन्सर्ट से
जहां इंसर्ट किया गया।ExecuteID =tblExecuteStoredProcedure.ExecuteID
);
END;पी>
काफी कौर, वह ट्रिगर। मूल रूप से यह एक एकल सम्मिलन लेता है, फिर यह पता लगाता है कि पैरामीटर को उनके nvarchar (MAX) से कैसे परिवर्तित किया जाए, जैसा कि तालिका tblExecuteStoredProcedure पर संग्रहीत प्रक्रिया द्वारा आवश्यक वास्तविक प्रकार में परिभाषित किया गया है। निहित रूपांतरणों का उपयोग किया जाता है, और चूंकि यह एक sys.sp_executesql में लिपटा हुआ है, इसलिए यह विभिन्न प्रकार के डेटा प्रकारों के लिए अच्छी तरह से काम करता है, जब तक कि पैरामीटर मान स्वयं मान्य हैं। ध्यान दें कि हम चाहते हैं कि संग्रहीत कार्यविधि कोई परिणाम सेट न लौटाए। माइक्रोसॉफ्ट ट्रिगर्स को परिणाम सेट वापस करने की अनुमति देता है लेकिन जैसा कि उल्लेख किया गया है, यह गैर-मानक है और इसे बहिष्कृत कर दिया गया है। इसलिए SQL सर्वर के भविष्य के संस्करणों के साथ समस्याओं से बचने के लिए, हम उस संभावना को रोकते हैं। अंत में, हम तालिका को साफ़ करते हैं, इसलिए यह हमेशा खाली रहती है। आखिरकार, हम तालिका का दुरुपयोग कर रहे हैं; हम कोई डेटा संग्रहीत नहीं कर रहे हैं।
मैंने एक ट्रिगर का उपयोग करना चुना क्योंकि यह एक्सेस और SQL सर्वर के बीच राउंड ट्रिप की संख्या में कटौती करता है। अगर मैंने ट्रिगर के शरीर से टी-एसक्यूएल को संसाधित करने के लिए एक संग्रहीत प्रक्रिया का उपयोग किया था, तो इसका मतलब होगा कि तालिका में डालने के बाद मुझे इसे कॉल करना होगा और संभावित साइड इफेक्ट्स से भी निपटना होगा जैसे दो उपयोगकर्ता एक ही समय में सम्मिलित करना या एक रिकॉर्ड को पीछे छोड़कर एक त्रुटि।
ठीक है, लेकिन हम "टेबल" और उसके ट्रिगर का उपयोग कैसे करते हैं? यहीं पर हमें पूरी व्यवस्था स्थापित करने के लिए थोड़े से VBA कोड की आवश्यकता होती है…
Public Sub ExecuteWithLargeParameters( _
ProcedureSchema As String, _
ProcedureName As String, _
ParamArray Parameters() _
)
Dim db As DAO.Database
Dim rs As DAO.Recordset
डिम मैं जितना लंबा
डिम एल जितना लंबा
डिम यू जितना लंबा
सेट db =CurrentDb
सेट करें rs =db.OpenRecordset ("चयन करें * tblExecuteStoredProcedure से;", dbOpenDynaset, dbAppendOnly या dbSeeChanges)
rs.AddNew
rs.Fields(“ProcedureSchema”).Value =ProcessSchema
rs.Fields(“ProcedureName”).Value =ProcessName
l =LBound(पैरामीटर)
u =UBound(पैरामीटर)
के लिए i =l से u
rs.Fields(“Parameter” &i).Value =Parameters(i)
अगला
rs.अपडेट करें
सब खत्म करें
ध्यान दें कि हम ParamArray का उपयोग करते हैं जो हमें उतने पैरामीटर निर्दिष्ट करने की अनुमति देता है जितने की हमें वास्तव में एक संग्रहीत कार्यविधि के लिए आवश्यकता होती है। यदि आप पागल होना चाहते हैं और 20 और पैरामीटर हैं, तो आप तालिका में और फ़ील्ड जोड़ सकते हैं और ट्रिगर अपडेट कर सकते हैं और वीबीए कोड अभी भी काम करेगा। आप कुछ इस तरह कर पाएंगे:
ExecuteWithLargeParameters "dbo", "uspMyStoredProcedure", dteStartDate, dteEndDate, strSomeBigXMLDocument
उम्मीद है, लंबे समय तक समाधान आवश्यक नहीं होगा (विशेषकर यदि आप एक्सेस यूजरवॉइस पर जाते हैं और एक्सेस + एसक्यूएल / ओडीबीसी से संबंधित विभिन्न मदों को अपवोट करते हैं), लेकिन हम आशा करते हैं कि आपको यह उपयोगी लगेगा यदि आप खुद को उस स्थिति में पाते हैं जो हम हैं in. हमें इस समाधान या बेहतर दृष्टिकोण के लिए आपके द्वारा किए जा सकने वाले सुधारों के बारे में भी सुनना अच्छा लगेगा!