मैं टी-एसक्यूएल में वैरिएबल का उपयोग क्यों नहीं कर सकता जैसे मैं कल्पना करता हूं कि मैं कर सकता हूं?


18

मुझे माफ कर दो, मैं एक डेवलपर हूं जो एसक्यूएल की दुनिया में स्थानांतरित हो गया है। मुझे लगा कि मैं चर जोड़कर कुछ एसक्यूएल में सुधार कर सकता हूं लेकिन यह मेरी तरह काम नहीं करता था। क्या कोई मुझे बता सकता है कि यह काम क्यों नहीं करता है? मैं आसपास कोई काम नहीं करना चाहता, मैं उन कारणों को जानना चाहता हूं कि यह काम क्यों नहीं करता है जैसे मुझे लगता है कि मुझे यह सोचना चाहिए क्योंकि मुझे यकीन है कि एक अच्छा कारण है, लेकिन वर्तमान में यह मेरे ऊपर से बाहर नहीं निकलता है।

DECLARE @DatabaseName varchar(150)
SET @DatabaseName = 'MyAmazingDatabaseName'

CREATE DATABASE @DatabaseName
GO

USE @DatabaseName
GO

आपको उसके लिए गतिशील sql का उपयोग करने की आवश्यकता है। mssqltips.com/sqlservertip/1160/…
Stijn Wynants

3
हे टिप्पणी करने के लिए धन्यवाद, लेकिन मेरे सवाल के अनुसार, यह वह उत्तर नहीं है जिसकी मुझे तलाश है। मैं जानना चाहता हूं कि क्या कोई जानता है कि मैं ऐसा नहीं कर सकता जैसे मैंने दिखाया है।
15

2
क्योंकि USEएक पैरामीटर के साथ कमांड का उपयोग करना संभव नहीं है ।
टीटी।

2
पहले से दिए गए उत्तरों के अलावा, लेकिन अपने स्वयं के उत्तर के लिए पर्याप्त नहीं है, चर को वर्तमान बैच के अधिकतम भाग में स्कोप किया जाता है। (यदि यह SQL सर्वर की तुलना में अधिक संकीर्ण रूप से चरों को स्कोप करना संभव है, तो मुझे पता नहीं है।) तो आपके पास GOपहले ही घोषित चर गायब हो जाता है। आप SQLCMD चर में देखना चाहते हैं, जो आपके परिदृश्य पर लागू हो भी सकता है और नहीं भी।
बजे एक CVn

1
हम डेटाबेस नामों और स्तंभ नामों को स्ट्रिंग मान के रूप में देखते हैं, लेकिन SQL के संदर्भ में वे पहचानकर्ता हैं। आप जो प्रयास कर रहे हैं, वह x = 7 की अपेक्षा के समान होगा; 'x' = 7 जैसा ही होना; किसी और भाषा में जिस तरह एक कंप्यूटर भाषा बनाई जा सकती है, जो 'x' = 7 के साथ x = 7 के समान है, एक RDBMS बनाया जा सकता है जो Create Table X को 'Table' के समान बनाता है। लेकिन यह SQL नहीं होगा।
user1008646

जवाबों:


20

चरों के लिए प्रति पुस्तक ऑनलाइन पेज

चर का उपयोग केवल भावों में किया जा सकता है, वस्तु के नाम या कीवर्ड के स्थान पर नहीं। डायनेमिक SQL स्टेटमेंट बनाने के लिए, EXECUTE का उपयोग करें।

यह उस तरह से काम करेगा जैसे आप उम्मीद कर रहे थे, उदाहरण के लिए, आपने अपने वैरिएबल का उपयोग एक क्लॉज में कहां किया है। क्यों के लिए, मुझे लगता है कि यह कुछ ऐसा है जो पार्सर के साथ चर का मूल्यांकन करने में सक्षम नहीं है और इस प्रकार अस्तित्व की जांच कर सकता है। निष्पादित करते समय, क्वेरी को पहले सिंटैक्स और ऑब्जेक्ट के लिए पार्स किया जाता है और फिर, यदि पार्सिंग सफल होता है, तो क्वेरी निष्पादित होती है कि किस बिंदु पर चर सेट किया जाएगा।

DECLARE @name varchar(20);
SET @name = 'test';

CREATE TABLE [#tmp]([val] varchar(10));

insert into #tmp
values('test')

SELECT *
FROM [#tmp]
WHERE [val] = @name;

3
ध्यान दें कि जब भी संभव हो डायनेमिक SQL से बचना चाहिए। यह evalजावास्क्रिप्ट और पायथन जैसी प्रक्रियात्मक भाषाओं में कार्यों का उपयोग करने के लिए एसक्यूएल एनालॉग है । यह सुरक्षा छेद बनाने का एक त्वरित तरीका है।
jpmc26

1
@ jpmc26: ऐसा करने के लिए और अधिक सुरक्षित तरीका क्या है जिसमें गतिशील एसक्यूएल शामिल नहीं है?
रॉबर्ट हार्वे

1
@RobertHarvey सिर्फ इसलिए कि यह सबसे अच्छा बचा है इसका मतलब यह नहीं है कि हमेशा एक ही कार्यक्षमता के साथ एक विकल्प है। ;) अक्सर, जवाब का हिस्सा है, "समस्या का पूरी तरह से अलग समाधान का उपयोग करें।" कभी-कभी यह करना सबसे अच्छी बात है, लेकिन बिना किसी विचार-विमर्श के अच्छी मात्रा में नहीं और सुनिश्चित करें कि आपने विकल्पों की उपेक्षा नहीं की है, और फिर भी, यह सावधानी की स्वस्थ खुराक के साथ आना चाहिए।
jpmc26

2
@ jpmc26: ओपी का उदाहरण दिखता है कि एक "कोड-फर्स्ट" ORM डेटाबेस में टेबल सेट करने के लिए क्या कर सकता है। जबकि गतिशील SQL सिद्धांत रूप में असुरक्षित है, अंत-उपयोगकर्ता कभी भी उस विशेष कोड को नहीं छूएगा।
रॉबर्ट हार्वे

@RobertHarvey निर्भर करता है कि आप "अंतिम उपयोगकर्ता" किसे मानते हैं। एक स्क्रिप्ट के लिए जो एक DB को दर्शाती है, मैं डेवलपर पर विचार करूंगा और संभवत: कुछ एसईएस व्यवस्थापक "अंतिम उपयोगकर्ता" होंगे। मैं अभी भी उस मामले में असुरक्षित इनपुट को अस्वीकार करने के लिए सिस्टम को डिज़ाइन करूंगा, अगर दुर्घटनाओं से बचने के लिए कोई अन्य कारण नहीं है। इसके अलावा, के रूप में "कभी नहीं छूने के लिए," ओपी इस कोड को छू रहा है, इसलिए ...
jpmc26

17

SQL कथनों में चर के उपयोग की सीमाएँ SQL की वास्तुकला से उत्पन्न होती हैं।

SQL कथन के प्रसंस्करण में तीन चरण होते हैं:

  1. तैयारी - बयान को पार्स किया गया है और एक निष्पादन योजना तैयार की गई है, जिसमें निर्दिष्ट किया गया है कि कौन से डेटाबेस ऑब्जेक्ट एक्सेस किए जाते हैं, वे कैसे एक्सेस किए जाते हैं और वे कैसे संबंधित हैं। निष्पादन योजना को योजना कैश में सहेजा गया है ।
  2. बंधन - बयान में किसी भी चर को वास्तविक मूल्यों के साथ बदल दिया जाता है।
  3. निष्पादन - कैश्ड योजना को बाध्य मूल्यों के साथ निष्पादित किया जाता है।

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

तो स्टेटिक एसक्यूएल में , चर का उपयोग केवल उन जगहों पर किया जा सकता है जहां वे निष्पादन योजना को अमान्य नहीं करेंगे, इसलिए तालिका के नाम, स्तंभ के नाम (WHERE की स्थितियों में स्तंभ के नाम सहित) के लिए नहीं, आदि।

डायनेमिक SQL उन मामलों के लिए मौजूद है, जहां कोई प्रतिबंधों को पूरा नहीं कर सकता है, और प्रोग्रामर जानता है कि इसे निष्पादित करने में थोड़ा अधिक समय लगेगा। डायनामिक SQL दुर्भावनापूर्ण कोड इंजेक्शन के लिए असुरक्षित हो सकता है, इसलिए ध्यान रखें!


7

जैसा कि आप देख सकते हैं, "क्यों" प्रश्न के लिए ऐतिहासिक तर्क और भाषा के लिए अंतर्निहित मान्यताओं सहित एक अलग तरह के उत्तर की आवश्यकता है, मुझे यकीन नहीं है कि मैं वास्तव में उस न्याय को कर सकता हूं।

SQL MVP Erland Sommarskog का यह व्यापक लेख मैकेनिक के साथ कुछ तर्क प्रदान करने का प्रयास करता है:

गतिशील एसक्यूएल का अभिशाप और आशीर्वाद :

कैशिंग क्वेरी योजनाएं

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

यह (और सुरक्षा, नीचे देखें) शायद सबसे बड़ा कारण है।

SQL इस आधार पर संचालित होता है कि क्वेरी एक बार के संचालन नहीं हैं, लेकिन यह कि उनका उपयोग बार-बार किया जाएगा। यदि तालिका (या डेटाबेस!) वास्तव में क्वेरी में निर्दिष्ट नहीं है, तो भविष्य के उपयोग के लिए निष्पादन योजना बनाने और बचाने का कोई तरीका नहीं है।

हां, हमारे द्वारा चलाए जाने वाले प्रत्येक क्वेरी का पुनः उपयोग नहीं किया जाएगा, लेकिन यह SQL का डिफ़ॉल्ट ऑपरेटिंग आधार है , इसलिए "अपवाद" असाधारण होने के लिए हैं।

एर्लैंड सूचियों के कुछ अन्य कारण (ध्यान दें कि वह संग्रहीत प्रक्रियाओं का उपयोग करने के लाभों को स्पष्ट रूप से सूचीबद्ध कर रहा है , लेकिन इनमें से कई पैरामीटरयुक्त (गैर-गतिशील) प्रश्नों के भी लाभ हैं):

  • अनुमति प्रणाली : SQL इंजन यह अनुमान नहीं लगा सकता है कि आपके पास क्वेरी चलाने का अधिकार है या नहीं, यदि वह उस तालिका (या डेटाबेस) को नहीं जानता है जिसके खिलाफ आप काम कर रहे होंगे। गतिशील एसक्यूएल का उपयोग करते हुए "अनुमति श्रृंखला" बट में दर्द होता है।
  • नेटवर्क ट्रैफ़िक को कम करना : स्टोर किए गए प्रॉप का नाम और नेटवर्क पर कुछ पैरामीटर मान पास करना एक लंबे क्वेरी स्टेटमेंट से कम है।
  • एनकैप्सुलेटिंग लॉजिक : आपको अन्य प्रोग्रामिंग वातावरणों से तर्क-वितर्क के फायदों से परिचित होना चाहिए।
  • क्या उपयोग किया जाता है, इस पर नज़र रखना : अगर मुझे कॉलम की परिभाषा बदलने की आवश्यकता है, तो मुझे उस सभी कोड को कैसे पता चल सकता है जो इसे कॉल करता है? सिस्टम प्रक्रियाएँ SQL डेटाबेस में निर्भरताएँ खोजने के लिए मौजूद होती हैं, लेकिन केवल तभी जब कोड संग्रहीत प्रक्रियाओं में हो।
  • एसक्यूएल कोड लिखने में आसानी : सिंटैक्स चेक तब होता है जब आप एक संग्रहीत प्रक्रिया बनाते हैं या संशोधित करते हैं, इसलिए उम्मीद है कि कम त्रुटियों का परिणाम होगा।
  • कीड़े और समस्याओं को संबोधित करना : एक डीबीए कभी-कभी गतिशील एसक्यूएल की तुलना में व्यक्तिगत संग्रहीत प्रक्रियाओं के प्रदर्शन को बहुत आसानी से ट्रेस और माप सकता है।

फिर, इनमें से प्रत्येक की सौ बारीकियाँ हैं जो मुझे यहाँ नहीं मिलेंगी।


2

आपको गतिशील sql का उपयोग करने की आवश्यकता है

DECLARE @DatabaseName varchar(150) = 'dbamaint'
declare @sqltext nvarchar(max) = N''

set @sqltext = N'CREATE DATABASE '+quotename(@DatabaseName)+ ';'

print @sqltext 

-- once you are happy .. uncomment below
--exec sp_executesql @sqltext
set @sqltext = ''
set @sqltext = N'use '+quotename(@DatabaseName)+ ';'
print @sqltext 
-- once you are happy .. uncomment below
--exec sp_executesql @sqltext

नीचे प्रिंट का आउटपुट है .. एक बार जब आप exec sp_executesql @sqltextस्टेटमेंट को अनसुना कर देंगे तो वास्तव में निष्पादित हो जाएगा ...

CREATE DATABASE [dbamaint];
use [dbamaint];

1
हाँ धन्यवाद, मुझे पता है कि, लेकिन मैं जानना चाहता हूं कि क्या कोई जानता है कि आप सिर्फ चर का उपयोग क्यों नहीं कर सकते?
गैरेथ

T-SQL पार्सर सिंटैक्स त्रुटियों को फेंक देगा। यह मान्य टी-एसक्यूएल नहीं है जिसे पार्सर पहचानता है।
परिजन शाह

धन्यवाद किन, मुझे यकीन है कि इसके लिए अच्छे कारण होने चाहिए। हो सकता है कि क्योंकि डेटाबेस के नाम में '@' हो सकता है और शायद कुछ और जटिल कारण हैं।
१६

1
हाँ, वे @ शामिल कर सकते हैं और मुझे लगता है कि यह मुख्य कारण है। msdn.microsoft.com/en-us/library/ms175874.aspx
Paweł Tajs

1
@gazeranco मेरा विश्वास करो, SQL Server के साथ काम करने वाले किसी भी व्यक्ति को कोई संदेह नहीं है कि अधिक कमांड निरंतर पहचानकर्ताओं के स्थान पर चर स्वीकार करेंगे।
db2
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.