सीएलआर का उपयोग किए बिना डेटाबेस स्तर स्थिरांक (गणना) बनाएं?


9

मेरे पास कई SQL ऑब्जेक्ट हैं जिन्हें अनुरोध की वांछित स्थिति के आधार पर वैकल्पिक कार्रवाई करने की आवश्यकता है। क्या डेटाबेस स्तर स्थिरांक (गणना) बनाने का एक तरीका है जो संग्रहीत प्रक्रियाओं, तालिका-मूल्यवान कार्यों को पारित किया जा सकता है, और प्रश्नों में उपयोग किया जा सकता है (सीएलआर का उपयोग किए बिना)?

CREATE PROCEDURE dbo.DoSomeWork(@param1 INTEGER, ..., @EnumValue myEnumType)  AS ...;

और फिर इसका उपयोग करें:

EXEC doSomeWork 85, ..., (myEnumType.EnumValue1 + myEnumType.EnumValue2);

जहां myEnumTypeकुछ गणना मूल्यों को रखा जाएगा।

इस प्रक्रिया में मैं आवश्यक कार्य करने के लिए @EnumValueमूल्यों के विरुद्ध इसका उपयोग और परीक्षण कर सकूंगा myEnumType। मैं myEnumTypeजिस मामले पर विचार कर रहा हूं, उसके लिए मैं एक बिटमास्क का मान बनाऊंगा।

एक सरल उदाहरण के लिए, एक महंगी प्रक्रिया पर विचार करें जो एक विशाल डेटासेट लेती है और इसे छोटे लेकिन फिर भी बहुत बड़े डेटासेट में घटा देती है। इस प्रक्रिया में आपको उस प्रक्रिया के बीच में कुछ समायोजन करने की आवश्यकता होती है जो परिणाम को प्रभावित करेगा। यह कहें कि कमी के भीतर एक मध्यवर्ती गणना की कुछ स्थिति के आधार पर कुछ प्रकार के रिकॉर्ड के लिए (या विरुद्ध) फ़िल्टर है। इसके लिए परीक्षण करने के लिए @EnumValueप्रकार myEnumTypeका उपयोग किया जा सकता है

SELECT   ...
FROM     ...
WHERE       (@EnumValue & myEnumType.EnumValue1 = myEnumType.EnumValue1 AND ...)
        OR  (@EnumValue & myEnumType.EnumValue2 = myEnumType.EnumValue2 AND ...)
        OR  ...

क्या सीएलआर के उपयोग के बिना SQL सर्वर में डेटाबेस स्तर की निरंतरता संभव है?

मैं एक डेटाबेस स्तर की गणना या स्थिरांक के सेट की मांग कर रहा हूं जिसे संग्रहीत प्रक्रियाओं, कार्यों और इतने पर मापदंडों के रूप में पारित किया जा सकता है।

जवाबों:


9

आप XML स्कीमा का उपयोग करके SQL सर्वर में एक गणन प्रकार बना सकते हैं।

उदाहरण के लिए रंग।

create xml schema collection ColorsEnum as '
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
    <xs:element name="Color">
        <xs:simpleType>
            <xs:restriction base="xs:string"> 
                <xs:enumeration value="Red"/>
                <xs:enumeration value="Green"/>
                <xs:enumeration value="Blue"/>
                <xs:enumeration value="Yellow"/>
            </xs:restriction> 
        </xs:simpleType>
    </xs:element>
</xs:schema>';

यह आपको एक प्रकार के चर या पैरामीटर का उपयोग करने की अनुमति देता है xml(dbo.ColorsEnum)

declare @Colors xml(dbo.ColorsEnum);
set @Colors = '<Color>Red</Color><Color>Green</Color>'

यदि आप कुछ ऐसा जोड़ने की कोशिश करते हैं जो रंग नहीं है

set @Colors = '<Color>Red</Color><Color>Ferrari</Color>';

आपको एक त्रुटि मिलती है।

Msg 6926, Level 16, State 1, Line 43
XML Validation: Invalid simple type value: 'Ferrari'. Location: /*:Color[2]

XML का निर्माण करना थोडा थकाऊ हो सकता है इसलिए आप उदाहरण के लिए एक सहायक दृश्य बना सकते हैं जो अनुमत मूल्यों को भी रखता है।

create view dbo.ColorsConst as
select cast('<Color>Red</Color>' as varchar(100)) as Red,
       cast('<Color>Green</Color>' as varchar(100)) as Green,
       cast('<Color>Blue</Color>' as varchar(100)) as Blue,
       cast('<Color>Yellow</Color>' as varchar(100)) as Yellow;

और एन्यूमरेशन बनाने के लिए इसे इस तरह से उपयोग करें।

set @Colors = (select Red+Blue+Green from dbo.ColorsConst);

यदि आप XML स्कीमा से गतिशील रूप से दृश्य बनाना चाहते हैं तो आप इस क्वेरी के साथ रंगों को निकाल सकते हैं।

select C.Name
from (select xml_schema_namespace('dbo','ColorsEnum')) as T(X)
  cross apply T.X.nodes('//*:enumeration') as E(X)
  cross apply (select E.X.value('@value', 'varchar(100)')) as C(Name);

गणन बेशक कार्यों और प्रक्रियाओं के मापदंडों के रूप में भी इस्तेमाल किया जा सकता है।

create function dbo.ColorsToString(@Colors xml(ColorsEnum))
returns varchar(100)
as
begin
  declare @T table(Color varchar(100));

  insert into @T(Color)
  select C.X.value('.', 'varchar(100)')
  from @Colors.nodes('Color') as C(X);

  return stuff((select ','+T.Color
                from @T as T
                for xml path('')), 1, 1, '');
end
create procedure dbo.GetColors
  @Colors xml(ColorsEnum)
as
select C.X.value('.', 'varchar(100)') as Color
from @Colors.nodes('Color') as C(X);
declare @Colors xml(ColorsEnum) = '
<Color>Red</Color>
<Color>Blue</Color>
';

select dbo.ColorsToString(@Colors);

set @Colors = (select Red+Blue+Green from dbo.ColorsConst);
exec dbo.GetColors @Colors;

6

जब से आप जाहिरा तौर पर SQL सर्वर 2016 का उपयोग कर रहे हैं, मैं एक और ' संभव ' विकल्प को बाहर फेंकना चाहूंगा - SESSION_CONTEXT

SQL सर्वर 2016 मेंSESSION_CONTEXT लियोनार्ड लोबेल के लेख, शेयरिंग स्टेट इन एसक्यूएल सर्वर 2016 के बारे में कुछ बहुत अच्छी जानकारी है।

कुछ प्रमुख बिंदुओं का सारांश:

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

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

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

SESSION_CONTEXTउपयोग करने के लिए आसान है, बस एक वांछित कुंजी द्वारा मूल्य संग्रहीत करने के लिए sp_set_session_context को कॉल करें। जब आप ऐसा करते हैं, तो आप पाठ्यक्रम की कुंजी और मूल्य की आपूर्ति करते हैं, लेकिन आप read_only पैरामीटर को भी सही पर सेट कर सकते हैं। यह सत्र संदर्भ में मान को लॉक करता है, ताकि इसे कनेक्शन के शेष जीवनकाल के लिए नहीं बदला जा सके। इसलिए, उदाहरण के लिए, डेटाबेस कनेक्शन स्थापित करने के बाद कुछ सत्र संदर्भ मान सेट करने के लिए इस संग्रहीत कार्यविधि को कॉल करने के लिए क्लाइंट एप्लिकेशन के लिए यह आसान है। यदि एप्लिकेशन ऐसा करते समय read_only पैरामीटर सेट करता है, तो संग्रहीत कार्यविधियाँ और अन्य T-SQL कोड जो तब सर्वर पर निष्पादित होता है, केवल मान को पढ़ सकते हैं, वे क्लाइंट पर चल रहे एप्लिकेशन द्वारा निर्धारित नहीं किया जा सकता।

परीक्षण के रूप में, मैंने एक सर्वर लॉगिन ट्रिगर बनाया जो कुछ CONTEXT_SESSIONजानकारी सेट करता है - एक के लिए SESSION_CONTEXTसेट किया गया था @read_only

DROP TRIGGER IF EXISTS [InitializeSessionContext] ON ALL SERVER
GO
CREATE TRIGGER InitializeSessionContext ON ALL SERVER
FOR LOGON AS

BEGIN

    --Initialize context information that can be altered in the session
    EXEC sp_set_session_context @key = N'UsRegion'
        ,@value = N'Southeast'

    --Initialize context information that cannot be altered in the session
    EXEC sp_set_session_context @key = N'CannotChange'
        ,@value = N'CannotChangeThisValue'
        ,@read_only = 1

END;

मैंने एक नए उपयोगकर्ता के रूप में लॉग इन किया और SESSION_CONTEXTजानकारी निकालने में सक्षम था :

DECLARE @UsRegion varchar(20)
SET @UsRegion = CONVERT(varchar(20), SESSION_CONTEXT(N'UsRegion'))
SELECT DoThat = @UsRegion

DECLARE @CannotChange varchar(20)
SET @CannotChange = CONVERT(varchar(20), SESSION_CONTEXT(N'CannotChange'))
SELECT DoThat = @CannotChange

मैंने भी 'read_only' संदर्भ जानकारी को बदलने का प्रयास किया:

EXEC sp_set_session_context @key = N'CannotChange'
    ,@value = N'CannotChangeThisValue'

और एक त्रुटि मिली:

Msg 15664, Level 16, State 1, Procedure sp_set_session_context, Line 1 [बैच स्टार्ट लाइन 8] सत्र संदर्भ में कुंजी 'CannotChange' सेट नहीं कर सकता। इस सत्र के लिए कुंजी को read_only के रूप में सेट किया गया है।

लॉगिन ट्रिगर ( इस पोस्ट से ) के बारे में एक महत्वपूर्ण नोट !

लॉगऑन ट्रिगर प्रभावी रूप से सभी उपयोगकर्ताओं के लिए डेटाबेस इंजन के सफल कनेक्शन को रोक सकता है, जिसमें sysadmin फिक्स्ड सर्वर भूमिका के सदस्य भी शामिल हैं। जब एक लॉगऑन ट्रिगर कनेक्शन को रोक रहा है, तो sysadmin निश्चित सर्वर भूमिका के सदस्य समर्पित प्रशासक कनेक्शन का उपयोग करके, या न्यूनतम कॉन्फ़िगरेशन मोड में डेटाबेस इंजन को शुरू करके कनेक्ट कर सकते हैं (-f)


एक संभावित दोष यह है कि यह सत्र संदर्भ उदाहरण विस्तृत (प्रति डेटाबेस नहीं) भरता है। इस बिंदु पर, एकमात्र विकल्प जो मैं सोच सकता हूं:

  1. Session_Contextडेटाबेस नाम के साथ प्रीफ़िक्स करके अपने नाम-मूल्य जोड़े को नाम दें ताकि दूसरे डेटाबेस में उसी प्रकार के नाम के लिए टकराव का कारण न हो। यह Session_Contextसभी उपयोगकर्ताओं के लिए सभी नाम-मानों को पूर्व-परिभाषित करने की समस्या को हल नहीं करता है ।
  2. जब लॉगिन ट्रिगर में आग लग जाती है, तो आपके पास EventData(xml) तक पहुंच होती है, जिसका उपयोग आप लॉगिन उपयोगकर्ता को निकालने के लिए कर सकते हैं और उसके आधार पर, आप विशिष्ट Session_Contextनाम-मूल्य जोड़े बना सकते हैं ।

4

SQL सर्वर में, नहीं (हालाँकि मुझे 1998 में Oracle पैकेजों में स्थिरांक बनाना याद है और SQL सर्वर में उनके होने से चूक गया है)।

और, मैंने अभी परीक्षण किया और पाया कि आप SQLCLR के साथ भी ऐसा नहीं कर सकते, कम से कम इस अर्थ में नहीं कि यह सभी मामलों में काम करेगा। होल्ड अप स्टोर्ड प्रोसीजर के मापदंडों पर प्रतिबंध है। ऐसा लगता है कि आप नहीं कर सकते हैं या तो एक .या ::पैरामीटर नाम में। मैंने कोशिश की:

EXEC MyStoredProc @ParamName = SchemaName.UdtName::[StaticField];

-- and:

DECLARE @Var = SchemaName.UdtName = 'something';
EXEC MyStoredProc @ParamName = @Var.[InstanceProperty];

दोनों ही मामलों में इसे पार्सिंग चरण (सत्यापित उपयोग SET PARSEONLY ON;) के कारण अतीत में नहीं मिला :

एमएसजी 102, स्तर 15, राज्य 1, लाइन xxxxx
'के पास गलत सिंटैक्स'। '

दूसरी ओर, दोनों विधियों ने उपयोगकर्ता-परिभाषित फ़ंक्शन मापदंडों के लिए काम किया:

SELECT MyUDF(SchemaName.UdtName::[StaticField]);

-- and:

DECLARE @Var = SchemaName.UdtName = N'something';
SELECT MyUDF(@Var.[InstanceProperty]);

तो, सबसे अच्छा आप वास्तव में यूसीएफ, टीवीएफ, यूडीए (मेरा मानना ​​है), और क्वेरी के साथ सीधे काम करने वाले SQLCLR का उपयोग कर सकते हैं, और तब संग्रहीत प्रक्रियाओं के साथ उपयोग करने की आवश्यकता होने पर स्थानीय चर को असाइन करें:

DECLARE @VarInt = SchemaName.UdtName::[StaticField];
EXEC MyStoredProc @ParamName = @VarInt;

यह वह तरीका है जो मैंने तब लिया है जब वास्तविक एनुम मान रखने का अवसर होता है (जैसा कि एक लुकअप वैल्यू के विपरीत जो कि इसके उपयोग / अर्थ के लिए एक लुकअप टेबल में होना चाहिए)।


"स्थिर" / "एनम" मान को थूकने के लिए यूजर-डिफाइंड फंक्शन (UDF) के साथ इस प्रयास के संबंध में, मुझे यह नहीं मिला कि मैं इसे स्टोर्ड प्रोसीजर पैरामीटर के रूप में पास करने के मामले में काम करूं:

EXEC MyStoredProc @ParamName = FunctionName(N'something');

SSMS को कोष्ठक के भीतर सब कुछ उजागर करने के साथ, "गलत सिंटैक्स" त्रुटि देता है, भले ही मैं स्ट्रिंग को एक नंबर, या सही कोष्ठक के साथ प्रतिस्थापित करता हूं, अगर इसमें पास होने के लिए कोई पैरामीटर नहीं है।

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