दिलचस्प पोस्ट
दो तर्कों के साथ decltype क्या है? किस प्रकार का उपयोग करें: jsonp ajax कॉल में "पोस्ट" नेट कोर, पोर्टेबल, स्टैंडर्ड, कॉम्पैक्ट, यूडब्ल्यूपी और पीसीएल के बीच का अंतर? कर्नल में न्यूनतम मैक्रो में "(शून्य) (& _min1 == & _min2)" का कार्य क्या है? उद्देश्य-सी में NSNotificationCenter के माध्यम से संदेश भेजें और प्राप्त करें? सी ++ प्रोग्रामर 'नए' का उपयोग कम क्यों करना चाहिए? Android "ऊंचाई" एक छाया नहीं दिखा रहा है कस्टम फेसबुक लॉगिन बटन – एंड्रॉइड डीएलएल से एक सी + + क्लास निर्यात करना मुद्रित फ्लोट को दशमलव अंकों के साथ 0 के पीछे वाले स्थान पर PHP में कॉल करने वाले पायथन getSize () मुझे त्रुटि दे रही है साझा प्राथमिकताएं "सीमा" Node.js / serverside javascript में एक .net DLL का उपयोग करना क्या IE के ClearAuthenticationCache के बराबर ब्राउज़र है?

कर्सर का उपयोग किए बिना प्रत्येक पंक्ति के लिए एसक्यूएल कॉल संग्रहित प्रक्रिया

एक तालिका में प्रत्येक पंक्ति के लिए एक संग्रहीत प्रक्रिया को कैसे कॉल किया जा सकता है, जहां एक पंक्ति के स्तंभ कर्सर का उपयोग किए बिना एप के इनपुट पैरामीटर हैं?

Solutions Collecting From Web of "कर्सर का उपयोग किए बिना प्रत्येक पंक्ति के लिए एसक्यूएल कॉल संग्रहित प्रक्रिया"

आम तौर पर मैं हमेशा एक सेट आधारित दृष्टिकोण (कभी-कभी स्कीमा बदलने की कीमत पर) की तलाश में हूं।

हालांकि, इस स्निपेट का स्थान है ..

-- Declare & init (2008 syntax) DECLARE @CustomerID INT = 0 -- Iterate over all customers WHILE (1 = 1) BEGIN -- Get next customerId SELECT TOP 1 @CustomerID = CustomerID FROM Sales.Customer WHERE CustomerID > @CustomerId ORDER BY CustomerID -- Exit loop if no more customers IF @@ROWCOUNT = 0 BREAK; -- call your sproc EXEC dbo.YOURSPROC @CustomerId END 

आप ऐसा कुछ कर सकते हैं: जैसे ग्राहक Sales.Customer ( Sales.Customer का उपयोग करते हैं। ग्राहक नमूना तालिका) के द्वारा अपनी तालिका का आदेश दें, और उन ग्राहकों को Sales.Customer जो एक WHILE लूप का उपयोग करते हैं:

 -- define the last customer ID handled DECLARE @LastCustomerID INT SET @LastCustomerID = 0 -- define the customer ID to be handled now DECLARE @CustomerIDToHandle INT -- select the next customer to handle SELECT TOP 1 @CustomerIDToHandle = CustomerID FROM Sales.Customer WHERE CustomerID > @LastCustomerID ORDER BY CustomerID -- as long as we have customers...... WHILE @CustomerIDToHandle IS NOT NULL BEGIN -- call your sproc -- set the last customer handled to the one we just handled SET @LastCustomerID = @CustomerIDToHandle SET @CustomerIDToHandle = NULL -- select the next customer to handle SELECT TOP 1 @CustomerIDToHandle = CustomerID FROM Sales.Customer WHERE CustomerID > @LastCustomerID ORDER BY CustomerID END 

यह किसी तालिका के साथ काम करना चाहिए, जब तक आप किसी कॉलम पर किसी प्रकार की ORDER BY परिभाषित कर सकते हैं।

 DECLARE @SQL varchar(max)='' -- MyTable has fields fld1 & fld2 Select @SQL = @SQL + 'exec myproc ' + convert(varchar(10),fld1) + ',' + convert(varchar(10),fld2) + ';' From MyTable EXEC (@SQL) 

ठीक है, इसलिए मैं कभी भी इस कोड को उत्पादन में नहीं डालूंगा, लेकिन यह आपकी आवश्यकताओं को पूरा करता है

मार्क का जवाब अच्छा है (मैं इसके बारे में टिप्पणी कर सकता हूं कि मैं कैसे काम कर सकता हूं!)
बस सोचा कि मैं कहना चाहता हूं कि लूप को बदलने के लिए बेहतर हो सकता है, इसलिए SELECT केवल एक बार होता है (एक वास्तविक मामले में जहां मुझे ऐसा करने की ज़रूरत थी, SELECT बहुत जटिल था, और इसे दो बार लिखना एक जोखिम भरा रखरखाव मुद्दा था) ।

 -- define the last customer ID handled DECLARE @LastCustomerID INT SET @LastCustomerID = 0 -- define the customer ID to be handled now DECLARE @CustomerIDToHandle INT SET @CustomerIDToHandle = 1 -- as long as we have customers...... WHILE @LastCustomerID <> @CustomerIDToHandle BEGIN SET @LastCustomerId = @CustomerIDToHandle -- select the next customer to handle SELECT TOP 1 @CustomerIDToHandle = CustomerID FROM Sales.Customer WHERE CustomerID > @LastCustomerId ORDER BY CustomerID IF @CustomerIDToHandle <> @LastCustomerID BEGIN -- call your sproc END END 

यदि आप संग्रहीत कार्यविधि को उस फ़ंक्शन में बदल सकते हैं जो तालिका लौटती है, तो आप क्रॉस-अप्लीकेशन का उपयोग कर सकते हैं।

उदाहरण के लिए, कहें कि आपके पास ग्राहकों की एक मेज है, और आप अपने ऑर्डर के योग की गणना करना चाहते हैं, तो आप एक ऐसा फ़ंक्शन बना सकते हैं जो ग्राहक आईडी लिया और राशि वापस कर दी।

और आप यह कर सकते हैं:

 SELECT CustomerID, CustomerSum.Total FROM Customers CROSS APPLY ufn_ComputeCustomerTotal(Customers.CustomerID) AS CustomerSum 

जहां समारोह ऐसा दिखेगा:

 CREATE FUNCTION ComputeCustomerTotal ( @CustomerID INT ) RETURNS TABLE AS RETURN ( SELECT SUM(CustomerOrder.Amount) AS Total FROM CustomerOrder WHERE CustomerID = @CustomerID ) 

जाहिर है, उपरोक्त उदाहरण एक ही क्वेरी में उपयोगकर्ता परिभाषित फ़ंक्शन के बिना किया जा सकता है।

दोष यह है कि फ़ंक्शन बहुत सीमित हैं – किसी संग्रहीत कार्यविधि की कई सुविधाएं उपयोगकर्ता-निर्धारित फ़ंक्शन में उपलब्ध नहीं हैं, और एक संग्रहीत कार्यविधि को किसी फ़ंक्शन में कनवर्ट करना हमेशा काम नहीं करती।

SQL सर्वर 2005 के लिए, आप ऐसा कर सकते हैं क्रॉस एप्लीकली और एक टेबल-मूल्य वाले फ़ंक्शन के साथ।

  • SQL सर्वर 2005 में क्रॉस एप्लिकेशन का उपयोग करना

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

यह उपरोक्त n3rd समाधान का एक भिन्नता है ORDER BY का उपयोग करके कोई सॉर्टिंग आवश्यक नहीं है, क्योंकि MIN () का उपयोग किया जाता है

याद रखें कि CustomerID (या जो भी अन्य संख्यात्मक कॉलम आप प्रगति के लिए उपयोग करते हैं) को एक अद्वितीय बाध्य होना चाहिए। इसके अलावा, यथासंभव यह संभव बनाने के लिए ग्राहकआईडी को अनुक्रमित किया जाना चाहिए।

 -- Declare & init DECLARE @CustomerID INT = (SELECT MIN(CustomerID) FROM Sales.Customer); -- First ID DECLARE @Data1 VARCHAR(200); DECLARE @Data2 VARCHAR(200); -- Iterate over all customers WHILE @CustomerID IS NOT NULL BEGIN -- Get data based on ID SELECT @Data1 = Data1, @Data2 = Data2 FROM Sales.Customer WHERE [ID] = @CustomerID ; -- call your sproc EXEC dbo.YOURSPROC @Data1, @Data2 -- Get next customerId SELECT @CustomerID = MIN(CustomerID) FROM Sales.Customer WHERE CustomerID > @CustomerId END 

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

यदि आप कर्सर का उपयोग नहीं करते हैं तो मुझे लगता है कि आपको इसे बाहरी रूप से करना होगा (तालिका प्राप्त करें, और फिर प्रत्येक कथन के लिए चलाएं और हर बार sp को बुलाएं) यह एक कर्सर का उपयोग करने के समान है, लेकिन केवल बाहर एसक्यूएल। आप कर्सर का उपयोग क्यों नहीं करेंगे?

मैं आमतौर पर इसे इस तरह करते हैं जब यह काफी कुछ पंक्तियां होती है:

  1. एसक्यूएल प्रबंधन स्टूडियो के साथ एक डाटासेट में सभी sproc पैरामीटर का चयन करें
  2. राइट-क्लिक करें -> कॉपी करें
  3. एक्सेल में पेस्ट करें
  4. एक एक्सेल कॉलम में '=' ​​एक्सीक स्कीमा। माइस्प्रक्रै @ परम = "और ए 2 'जैसे सूत्र के साथ सिंगल-पंक्ति एसक्यूएल स्टेटमेंट बनाएं। (जहां ए 2 पैरामीटर वाला आपकी एक्सेल कॉलम है)
  5. एसक्यूएल प्रबंधन स्टूडियो में एक नई क्वेरी में एक्सल स्टेटमेंट की सूची की प्रतिलिपि बनाएँ और निष्पादित करें।
  6. किया हुआ।

(बड़े डेटासेट पर मैं उपर्युक्त समाधानों में से एक का उपयोग करना चाहता हूं)।

DELIMITER //

 CREATE PROCEDURE setFakeUsers (OUT output VARCHAR(100)) BEGIN -- define the last customer ID handled DECLARE LastGameID INT; DECLARE CurrentGameID INT; DECLARE userID INT; SET @LastGameID = 0; -- define the customer ID to be handled now SET @userID = 0; -- select the next game to handle SELECT @CurrentGameID = id FROM online_games WHERE id > LastGameID ORDER BY id LIMIT 0,1; -- as long as we have customers...... WHILE (@CurrentGameID IS NOT NULL) DO -- call your sproc -- set the last customer handled to the one we just handled SET @LastGameID = @CurrentGameID; SET @CurrentGameID = NULL; -- select the random bot SELECT @userID = userID FROM users WHERE FIND_IN_SET('bot',baseInfo) ORDER BY RAND() LIMIT 0,1; -- update the game UPDATE online_games SET userID = @userID WHERE id = @CurrentGameID; -- select the next game to handle SELECT @CurrentGameID = id FROM online_games WHERE id > LastGameID ORDER BY id LIMIT 0,1; END WHILE; SET output = "done"; END;// CALL setFakeUsers(@status); SELECT @status; 

मैं स्वीकार किए जाते हैं उत्तर का उपयोग करता हूं, लेकिन एक अन्य संभावना है कि तालिका के मूल्यों के एक गिने गए सेट (इस मामले में सिर्फ एक तालिका का आईडी फ़ील्ड) रखने के लिए और पंक्ति संख्या में उन लोगों के माध्यम से जो तालिका में शामिल होने के लिए शामिल हो। लूप के भीतर कार्रवाई करने के लिए आपको जो भी ज़रूरत है उसे पुनः प्राप्त करें

 DECLARE @RowCnt int; SET @RowCnt = 0 -- Loop Counter -- Use a table variable to hold numbered rows containg MyTable's ID values DECLARE @tblLoop TABLE (RowNum int IDENTITY (1, 1) Primary key NOT NULL, ID INT ) INSERT INTO @tblLoop (ID) SELECT ID FROM MyTable -- Vars to use within the loop DECLARE @Code NVarChar(10); DECLARE @Name NVarChar(100); WHILE @RowCnt < (SELECT COUNT(RowNum) FROM @tblLoop) BEGIN SET @RowCnt = @RowCnt + 1 -- Do what you want here with the data stored in tblLoop for the given RowNum SELECT @Code=Code, @Name=LongName FROM MyTable INNER JOIN @tblLoop tL on MyTable.ID=tL.ID WHERE tl.RowNum=@RowCnt PRINT Convert(NVarChar(10),@RowCnt) +' '+ @Code +' '+ @Name END 

यह पहले से प्रदान किए गए उत्तरों पर भिन्नता है, लेकिन इसे बेहतर प्रदर्शन करना चाहिए क्योंकि इसे ORDER BY, COUNT या MIN / MAX की आवश्यकता नहीं है इस दृष्टिकोण के साथ एकमात्र नुकसान यह है कि आपको सभी आईडी पकड़ने के लिए एक अस्थायी तालिका तैयार करनी होगी (यह धारणा है कि आपके पास ग्राहक आईडी की सूची में अंतराल है)।

उसने कहा, मैं @ मार्क पावेल से सहमत हूं कि, आम तौर पर, एक सेट आधारित दृष्टिकोण अब भी बेहतर होगा।

 DECLARE @tmp table (Id INT IDENTITY(1,1) PRIMARY KEY NOT NULL, CustomerID INT NOT NULL) DECLARE @CustomerId INT DECLARE @Id INT = 0 INSERT INTO @tmp SELECT CustomerId FROM Sales.Customer WHILE (1=1) BEGIN SELECT @CustomerId = CustomerId, @Id = Id FROM @tmp WHERE Id = @Id + 1 IF @@rowcount = 0 BREAK; -- call your sproc EXEC dbo.YOURSPROC @CustomerId; END 

यदि मामले महत्वपूर्ण है तो

 --declare counter DECLARE @CurrentRowNum BIGINT = 0; --Iterate over all rows in [DataTable] WHILE (1 = 1) BEGIN --Get next row by number of row SELECT TOP 1 @CurrentRowNum = extendedData.RowNum --here also you can store another values --for following usage --@MyVariable = extendedData.Value FROM ( SELECT data.* ,ROW_NUMBER() OVER(ORDER BY (SELECT 0)) RowNum FROM [DataTable] data ) extendedData WHERE extendedData.RowNum > @CurrentRowNum ORDER BY extendedData.RowNum --Exit loop if no more rows IF @@ROWCOUNT = 0 BREAK; --call your sproc --EXEC dbo.YOURSPROC @MyVariable END 

इसके लिए एक बेहतर उपाय है

  1. संग्रहित प्रक्रिया की प्रतिलिपि / अतीत कोड
  2. तालिका के साथ उस कोड से जुड़ें जिसके लिए आप इसे फिर से चालू करना चाहते हैं (प्रत्येक पंक्ति के लिए)

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

मेरे पास कुछ प्रोडक्शन कोड था जो केवल एक बार में 20 कर्मचारी संभाल सकता था, नीचे कोड के लिए ढांचा है I मैं सिर्फ उत्पादन कोड की प्रतिलिपि बनाई और नीचे की गई सामग्री को निकाल दिया।

 ALTER procedure GetEmployees @ClientId varchar(50) as begin declare @EEList table (employeeId varchar(50)); declare @EE20 table (employeeId varchar(50)); insert into @EEList select employeeId from Employee where (ClientId = @ClientId); -- Do 20 at a time while (select count(*) from @EEList) > 0 BEGIN insert into @EE20 select top 20 employeeId from @EEList; -- Call sp here delete @EEList where employeeId in (select employeeId from @EE20) delete @EE20; END; RETURN end 

मुझे ऐसा कुछ करना पसंद है (हालांकि यह अभी भी कर्सर का उपयोग करने के समान है)

[कोड]

 -- Table variable to hold list of things that need looping DECLARE @holdStuff TABLE ( id INT IDENTITY(1,1) , isIterated BIT DEFAULT 0 , someInt INT , someBool BIT , otherStuff VARCHAR(200) ) -- Populate your @holdStuff with... stuff INSERT INTO @holdStuff ( someInt , someBool , otherStuff ) SELECT 1 , -- someInt - int 1 , -- someBool - bit 'I like turtles' -- otherStuff - varchar(200) UNION ALL SELECT 42 , -- someInt - int 0 , -- someBool - bit 'something profound' -- otherStuff - varchar(200) -- Loop tracking variables DECLARE @tableCount INT SET @tableCount = (SELECT COUNT(1) FROM [@holdStuff]) DECLARE @loopCount INT SET @loopCount = 1 -- While loop variables DECLARE @id INT DECLARE @someInt INT DECLARE @someBool BIT DECLARE @otherStuff VARCHAR(200) -- Loop through item in @holdStuff WHILE (@loopCount <= @tableCount) BEGIN -- Increment the loopCount variable SET @loopCount = @loopCount + 1 -- Grab the top unprocessed record SELECT TOP 1 @id = id , @someInt = someInt , @someBool = someBool , @otherStuff = otherStuff FROM @holdStuff WHERE isIterated = 0 -- Update the grabbed record to be iterated UPDATE @holdAccounts SET isIterated = 1 WHERE id = @id -- Execute your stored procedure EXEC someRandomSp @someInt, @someBool, @otherStuff END 

[/ कोड]

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