2010-01-16 20 views
35

के लिए संग्रहीत प्रक्रिया कॉल करें मैं एक चयन कथन के प्रत्येक रिकॉर्ड के लिए संग्रहीत प्रक्रिया को कॉल करने का एक तरीका ढूंढ रहा हूं।एसक्यूएल - प्रत्येक रिकॉर्ड

SELECT @SomeIds = (
    SELECT spro.Id 
    FROM SomeTable as spro 
    INNER JOIN [Address] addr ON addr.Id = spro.Id 
    INNER JOIN City cty ON cty.CityId = addr.CityId 
    WHERE cty.CityId = @CityId 
) 


WHILE @SomeIds IS NOT NULL 
BEGIN 
    EXEC UpdateComputedFullText @SomeIds 
END 

उपरोक्त ऐसी चीज बिल्कुल काम नहीं कर रही है, लेकिन ऐसा कुछ करने का कोई तरीका है?

+1

हर कोई पुनरावृत्ति से बचने के लिए भीख मांग रहा है (कर्सर या समय)। Sproc क्या करता है, तो हम एक सेट आधारित समाधान परिभाषित कर सकते हैं? – Precipitous

+0

मैंने अपना सेट आधारित दृष्टिकोण अन-हटा दिया है - पहले जल्दी में था और अंत में बिना 'नोट' के इसे रखना चाहता था। –

उत्तर

59

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

DECLARE @oneid int -- or the appropriate type 

DECLARE the_cursor CURSOR FAST_FORWARD 
FOR SELECT spro.Id 
    FROM SomeTable as spro 
     INNER JOIN [Address] addr ON addr.Id = spro.Id 
     INNER JOIN City cty ON cty.CityId = addr.CityId 
    WHERE cty.CityId = @CityId 

OPEN the_cursor 
FETCH NEXT FROM the_cursor INTO @oneid 

WHILE @@FETCH_STATUS = 0 
BEGIN 
    EXEC UpdateComputedFullText @oneid 

    FETCH NEXT FROM the_cursor INTO @oneid 
END 

CLOSE the_cursor 
DEALLOCATE the_cursor 
+3

ओपी को, ध्यान दें कि कर्सर बुरा हैं और आपको उन्हें हर कीमत से बचना चाहिए, लेकिन मैं अभी भी इसे +1 देता हूं क्योंकि इनका उपयोग कुछ मामलों में उचित हो सकता है। उम्मीद है कि यह एक बार की बात है और आप इस कर्सर को किसी अन्य प्रो के अंदर नहीं डाल पाएंगे :) –

+1

(-1) कर्सर बहुत ही खास हैं क्योंकि SQL सर्वर के नए संस्करण हैं। वह और सेट आधारित वाक्यविन्यास बहुत अधिक सुरुचिपूर्ण और संक्षेप है - तेजी से परिमाण के आदेशों पर आदेशों का उल्लेख नहीं करना। –

+22

कर्सर बुरा नहीं हैं - यह सरल है। यदि संभव हो, तो एक सेट आधारित समाधान का उपयोग कर पुनरावृत्त समाधान (कर्सर या जबकि loops) फिर से लिखें। अतिरिक्त जानकारी के बिना आपको इस मामले में फिर से शुरू करने की आवश्यकता है और एक कर्सर ठीक है। – Precipitous

1

आप एक कर्सर का उपयोग करना होगा: SQL Server Cursor Examples

DECLARE @id int 
DECLARE cursor_sample CURSOR FOR 
SELECT spro.Id 
FROM SomeTable as spro 
    INNER JOIN [Address] addr ON addr.Id = spro.Id 
    INNER JOIN City cty ON cty.CityId = addr.CityId 
WHERE cty.CityId = @CityId 

OPEN cursor_sample 
FETCH NEXT FROM cursor_sample INTO @id 
WHILE @@FETCH_STATUS = 0 
BEGIN 
    EXEC UpdateComputedFullText @id 
    FETCH NEXT FROM cursor_sample INTO @id 
END 

CLOSE cursor_sample 
DEALLOCATE cursor_sample 
14

अस्थायी तालिका चर में पुनरावृति सोचा प्रत्येक पंक्ति आईडी रखो, और उसके बाद:

Declare @Keys Table (key integer Primary Key Not Null) 
    Insert @Keys(key) 
    SELECT spro.Id 
    FROM SomeTable as spro 
     JOIN [Address] addr ON addr.Id = spro.Id 
     JOIN City cty ON cty.CityId = addr.CityId 
    WHERE cty.CityId = @CityId 
    -- ------------------------------------------- 
    Declare @Key Integer 
    While Exists (Select * From @Keys) 
    Begin 
     Select @Key = Max(Key) From @Keys 
     EXEC UpdateComputedFullText @Key 
     Delete @Keys Where Key = @Key 
    End 

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

Declare @Key Integer = 0 
While Exists (Select * From @Keys 
       Where key > @Key) 
Begin 
    Select @Key = Min(Key) From @Keys 
        Where key > @Key 
    EXEC UpdateComputedFullText @Key 
    -- Delete @Keys Where Key = @Key No Longer necessary 
End  
+0

यह एक दिलचस्प दृष्टिकोण है। :) – treaschf

+1

ठीक है, कर्सर धीमे हैं, लेकिन क्या यह तेज़ है? –

+0

मुझे यह पसंद है। कर्सर बुराई हैं। :) –

2

आरई कर्सर के ऊपर दोनों उत्तर सही हैं। हालांकि, कर्सर के अंदर चल रहे कोड की जटिलता के आधार पर, आप इसे अपनी पसंद की भाषा में छोड़ने और डेटाबेस में परिणामों को छोड़ने से पहले कोड में अपनी गणना करने में बेहतर सेवा कर सकते हैं।

मुझे खुद को वापस जाना और कर्सर परिचालनों की समीक्षा करना पाया गया है, और कई मामलों में, इन्हें प्रदर्शन कारणों से कोड में स्थानांतरित करना है।

2

कर्सर के बिना यह एक प्रयास करें

DECLARE @id int 

SELECT top 1 @id = spro.Id 
    FROM SomeTable as spro 
     INNER JOIN [Address] addr ON addr.Id = spro.Id 
     INNER JOIN City cty ON cty.CityId = addr.CityId 
    WHERE cty.CityId = @CityId 
    ORDER BY spro.id 

WHILE @@ROWCOUNT > 0 
BEGIN 
    EXEC UpdateComputedFullText @id 

    SELECT top 1 @id = spro.Id 
    FROM SomeTable as spro 
     INNER JOIN [Address] addr ON addr.Id = spro.Id 
     INNER JOIN City cty ON cty.CityId = addr.CityId 
    WHERE cty.CityId = @CityId 
    and spro.id > @id 
    ORDER BY spro.id 
END 
+0

यह कारण के बिना सिद्धांत है - कानून की भावना के बजाय कानून का पत्र। कर्सर से बचने का प्राथमिक कारण यह है कि लगभग हमेशा एक अधिक कुशल सेट आधारित समाधान होता है। यह कर्सर से बचाता है लेकिन सेट आधारित समाधान प्रदान नहीं करता है। बेशक, हम नहीं जानते कि इस समस्या के लिए एक सेट आधारित समाधान मौजूद है। – Precipitous

+0

(+1) मुझे अपने सहयोगियों ने बताया है कि एसक्यूएल में टेराबाइट स्केल डेटा प्रोसेसिंग करते हैं कि पुनरावृत्ति के लिए 'WHILE' काफी अच्छा प्रदर्शन करता है - खासकर जब कोई विकल्प नहीं रहता है - इन दिनों हालांकि टीवीएफ + क्रॉस लागू = राजा (मेरा जवाब देखें)। –

0

तुम सच में जब सेट प्रसंस्करण उपलब्ध है पंक्ति-दर-पंक्ति प्रसंस्करण करने की ज़रूरत है?

आप SELECT के परिणामों को एक temp तालिका में डाल सकते हैं, फिर temp तालिका की सामग्री के विरुद्ध थोक SQL निष्पादित करने के लिए एक प्रो कॉल करें। अस्थायी तालिका टी-एसक्यूएल स्कोपिंग नियमों के आधार पर बुलाए गए प्रो को उपलब्ध होगी।

18

आश्चर्यचकित कोई भी आपको एक अद्यतित उत्तर नहीं देता है। कर्सर खराब हैं। आप जो चाहते हैं वह एसपी के तर्क को table-valued-function(TVF) and then use CROSS APPLY

यहां एक प्रश्न है जिसे मैंने कल लिखा था (विवरण पर ध्यान न दें, बस CROSS APPLY देखें)। CROSS APPLY टेबल का एक संघ बनाता है। इस संघ का प्रत्येक तत्व टीवीएफ से उत्पन्न होता है जिसे चयन कथन की पंक्ति प्रविष्टियों पर पैरामीटर किया जाता है।

SELECT supt.hostname,supt.scriptname, COUNT(*) 
FROM Event_Pagehit eph 
    INNER JOIN Symboltable_urlpair supf 
    ON eph.fromPagePair=supf.id 
    INNER JOIN Symboltable_urlpair supt 
    ON supt.id=eph.toPagePair 
CROSS APPLY dbo.TDFCompanyFormationsUrlClassification(supf.hostname,supf.scriptname) as x 
CROSS APPLY dbo.TDFCompanyFormationsUrlClassification(supt.hostname,supt.scriptname) as y 
WHERE x.isCompanyFormations=1 
AND y.isCompanyFormations=0 
GROUP BY supt.hostname,supt.scriptname 
ORDER BY COUNT(*) desc 

मैं x और y उपयोग कर सकते हैं जैसे कि वे थे टेबल FROM या JOIN खंड से हासिल कर लिया। अगर मुझे टीवीएफ के बिना यह प्रश्न लिखना पड़ा तो यह कुछ सौ लाइनों तक फैल जाएगा।

नोट:

आप को फिर से लिखने नहीं कर सकते सपा: यदि आप एक मेज महत्वपूर्ण समारोह से परिणाम तालिका में एक संग्रहीत प्रक्रिया का परिणाम सम्मिलित करने के लिए सक्षम होना चाहिए। मैंने कभी ऐसा नहीं किया है, और कभी-कभी अलग-अलग SQL सर्वर निर्माण में चेतावनी होती है - इसलिए जब तक कि कोई अन्य कहता है, मुझे लगता है कि यह मामला है।

+0

(+1) मैं हमेशा नए समाधान के लिए खुला रहता हूं, विशेष रूप से यदि वे आधार सेट हैं। –

+0

इस बारे में प्रश्न? क्या 'क्रॉस आवेदन' कहां से पहले या उसके बाद होता है? मुझे पता है कि इसे कथन में कहां रखा जाए, लेकिन क्या यह नीचे * WHERE' से पूर्व-फ़िल्टर किए गए या पोस्ट-फ़िल्टर किए गए आइटमों का उपयोग करके * निष्पादित * करता है? – SnareChops

+0

यह कैसे लागू होता है यदि आप एक ऐसी प्रक्रिया का उपयोग करते हैं जो परिणाम सेट नहीं लौटाता है? मान लें कि आप userUser (जैसे सदस्यता ढांचे में एएसपीनेट) नामक एक प्रो में उपयोगकर्ता आईडी की एक सूची पाइप कर रहे थे, आप लगभग कर्सर या कथन के दौरान अटक गए हैं, नहीं? – Andrew

0

मानक कर्सर समाधान बुराई पर बुराई है। दो समान फ़ेच अगला विवरण केवल एक रखरखाव दुःस्वप्न हैं।

बेहतर

...declare cursor etc. 
While 1=1 
Fetch ... 
if @@FETCH_STATUS <> 0 BREAK 
... 
End -- While 
..Close cursor etc. 

दुष्ट कभी कभी उचित है। sp_send_dbmail या अन्य संग्रहीत प्रक्रिया का उपयोग कर अधिसूचना ईमेल भेजने के लिए बस सेट आधारित दृष्टिकोण तैयार करने का प्रयास करें।

संबंधित मुद्दे