2009-10-16 17 views
56

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

DECLARE @table1 TABLE (col1 int) 
INSERT into @table1 SELECT col1 FROM table2 

मैं भी कर्सर उपयोग करें, लेकिन कर्सर तालिका चर से कम लचीला लग रहे हैं।

DECLARE cursor1 CURSOR 
    FOR SELECT col1 FROM table2 
OPEN cursor1 
FETCH NEXT FROM cursor1 

मैं एक कर्सर के समान तरीके से तालिका सारणी का उपयोग करने में सक्षम होना चाहता हूं। इस तरह से मैं प्रक्रिया के एक भाग में तालिका चर पर कुछ क्वेरी निष्पादित कर सकता हूं, और बाद में तालिका चर में प्रत्येक पंक्ति के लिए कुछ कोड निष्पादित कर सकता हूं।

किसी भी मदद की बहुत सराहना की जाती है।

+0

समान यहाँ प्रश्न: http://stackoverflow.com/questions/61967/is-there-a-way-to-loop-through-a-table-variable-in-tsql-without-using-a- कर्सर – demp

+2

"कर्सर तालिका चर से कम लचीला प्रतीत होता है"। यह कथन वास्तव में समझ में नहीं आता है। वे पूरी तरह से अलग चीजें हैं। आप निश्चित रूप से एक तालिका चर के माध्यम से पुनरावृत्त करने के लिए एक कर्सर का उपयोग कर सकते हैं। –

उत्तर

79

अपनी मेज चर करने के लिए एक पहचान जोड़ें, और सम्मिलित करें-चयन की @@ ROWCOUNT 1 से एक आसान पाश है।

इस प्रयास करें:

DECLARE @RowsToProcess int 
DECLARE @CurrentRow  int 
DECLARE @SelectCol1  int 

DECLARE @table1 TABLE (RowID int not null primary key identity(1,1), col1 int) 
INSERT into @table1 (col1) SELECT col1 FROM table2 
SET @[email protected]@ROWCOUNT 

SET @CurrentRow=0 
WHILE @CurrentRow<@RowsToProcess 
BEGIN 
    SET @[email protected]+1 
    SELECT 
     @SelectCol1=col1 
     FROM @table1 
     WHERE [email protected] 

    --do your thing here-- 

END 
+4

यह बहुत सरलता की तरह लगता है। धन्यवाद! – Kuyenda

12
DECLARE @table1 TABLE (
    idx int identity(1,1), 
    col1 int) 

DECLARE @counter int 

SET @counter = 1 

WHILE(@counter < SELECT MAX(idx) FROM @table1) 
BEGIN 
    DECLARE @colVar INT 

    SELECT @colVar = col1 FROM @table1 WHERE idx = @counter 

    -- Do your work here 

    SET @counter = @counter + 1 
END 

मानो या नहीं, यह वास्तव में एक कर्सर का उपयोग करने से अधिक कुशल और निष्पादक है।

+0

लूप में प्रत्येक बार अधिकतम का चयन क्यों करें? –

+0

आप इसे एक बार चुन सकते हैं और उसे आसानी से एक चर में स्टोर कर सकते हैं ... यह केवल कुछ कीस्ट्रोक कम था। –

+1

लूप में प्रत्येक बार अधिकतम का चयन क्यों करें? नतीजतन, आपको प्रतिरक्षा के दो बार तालिका चर को हिट करना होगा। यदि आप तालिका में व्यवहार्य आबादी से @@ ROWCOUNT को कैप्चर करते हैं, तो आप SELECT MAX() में SELECT MAX() को हटा सकते हैं, जैसे कि मैं अपने उत्तर में करता हूं। –

6

आप तालिका चर के माध्यम से लूप कर सकते हैं या आप इसके माध्यम से कर्सर कर सकते हैं। यही वह है जिसे हम आमतौर पर आरबीएआर - स्पष्ट रीबर कहते हैं और इसका अर्थ है रो-बाय-एगोनिंग-रो।

मैं आपके प्रश्न के लिए सेट-आधारित जवाब ढूंढने का सुझाव दूंगा (हम इसके साथ मदद कर सकते हैं) और जितना संभव हो उतना आरबीआर से दूर चले जा सकते हैं।

+0

यह वास्तव में क्यों है कि मैं एक कर्सर की बजाय तालिका चर का उपयोग करना चाहता हूं। मैं आमतौर पर टेबल वैरिएबल पर जॉइन का उपयोग करके अपना इच्छित परिणाम प्राप्त करने का एक तरीका ढूंढता हूं, लेकिन अगर मुझे जॉइन का उपयोग करने का कोई तरीका नहीं मिल रहा है, तो मैं उसी टेबल वैरिएबल पर लूप पर वापस आ सकता हूं। लेकिन मैं सहमत हूं, सेट-आधारित सबसे अच्छा है। – Kuyenda

+0

तालिका चर पर लूपिंग कर्सर से बेहतर नहीं है। वास्तव में, यह वास्तव में बदतर हो सकता है। कर्सर से लूप तक कोड बदलने का एकमात्र असली लाभ "उग्र अधिकार" है। पूर्व: "मेरे पास मेरे कोड में कोई कर्सर नहीं है"। –

2

जस्टिन के समान एक और जवाब है, लेकिन पहचान या कुल की आवश्यकता नहीं है, केवल एक प्राथमिक (अद्वितीय) कुंजी।

declare @table1 table(dataKey int, dataCol1 varchar(20), dataCol2 datetime) 
declare @dataKey int 
while exists select 'x' from @table1 
begin 
    select top 1 @dataKey = dataKey 
    from @table1 
    order by /*whatever you want:*/ dataCol2 desc 

    -- do processing 

    delete from @table1 where dataKey = @dataKey 
end 
+0

प्रत्येक पुनरावृत्ति आपने टेबल वैरिएबल को 3 बार मारा, जो कि कुशल नहीं हो सकता –

2

यहाँ मेरी संस्करण है। अन्य सभी की तरह बहुत अधिक, लेकिन मैं केवल लूपिंग को प्रबंधित करने के लिए एक चर का उपयोग करता हूं।

DECLARE 
    @LoopId int 
,@MyData varchar(100) 

DECLARE @CheckThese TABLE 
(
    LoopId int not null identity(1,1) 
    ,MyData varchar(100) not null 
) 


INSERT @CheckThese (YourData) 
select MyData from MyTable 
order by DoesItMatter 

SET @LoopId = @@rowcount 

WHILE @LoopId > 0 
BEGIN 
    SELECT @MyData = MyData 
    from @CheckThese 
    where LoopId = @LoopId 

    -- Do whatever 

    SET @LoopId = @LoopId - 1 
END 

राज मोर का बिंदु प्रासंगिक है - केवल आपको लूप प्रदर्शन करना है।

2

मुझे WHILE संरचना के बारे में पता नहीं था।

तालिका तालिका के साथ WHILE संरचना, हालांकि, एक CURSOR का उपयोग करने के समान दिखती है, जिसमें आपको अभी भी पंक्ति पहचान के आधार पर एक चर में चयन करना है, जो प्रभावी रूप से एक FETCH है।

WHERE का उपयोग करने और निम्नलिखित में से कुछ के बीच कोई अंतर है?

DECLARE @table1 TABLE (col1 int) 
INSERT into @table1 SELECT col1 FROM table2 

DECLARE cursor1 CURSOR 
    FOR @table1 
OPEN cursor1 
FETCH NEXT FROM cursor1 

मुझे नहीं पता कि यह भी संभव है या नहीं। मुझे लगता है कि आपको यह करना पड़ सकता है:

DECLARE cursor1 CURSOR 
    FOR SELECT col1 FROM @table1 
OPEN cursor1 
FETCH NEXT FROM cursor1 

आपकी मदद के लिए धन्यवाद!

+1

आपका कोड: _DECLARE कर्सर 1 कर्सर @ table1 के लिए खोलें कर्सर 1_ काम नहीं करेगा। कर्सर को अपनी परिभाषा में एक चयन करना होगा, जैसे आपका दूसरा कोड उदाहरण। यदि आप कुछ परीक्षण करते हैं, तो आप पाएंगे कि एक कर्सर का उपयोग किए बिना लूपिंग कर्सर का उपयोग करके लूपिंग से तेज है। –

1

यहां एक ही समाधान का मेरा संस्करण है ...

declare @id int 

     SELECT @id = min(fPat.PatientID) 
     FROM tbPatients fPat 
     WHERE (fPat.InsNotes is not null AND DataLength(fPat.InsNotes)>0) 

while @id is not null 
begin 
    SELECT fPat.PatientID, fPat.InsNotes 
    FROM tbPatients fPat 
    WHERE (fPat.InsNotes is not null AND DataLength(fPat.InsNotes)>0) AND [email protected] 

    SELECT @id = min(fPat.PatientID) 
    FROM tbPatients fPat 
    WHERE (fPat.InsNotes is not null AND DataLength(fPat.InsNotes)>0)AND fPat.PatientID>@id 

end 
5

नज़र इस डेमो की तरह:

DECLARE @vTable TABLE (IdRow int not null primary key identity(1,1),ValueRow int); 

-------Initialize--------- 
insert into @vTable select 345; 
insert into @vTable select 795; 
insert into @vTable select 565; 
--------------------------- 

DECLARE @cnt int = 1; 
DECLARE @max int = (SELECT MAX(IdRow) FROM @vTable); 

WHILE @cnt <= @max 
BEGIN 
    DECLARE @tempValueRow int = (Select ValueRow FROM @vTable WHERE IdRow = @cnt); 

    ---work demo---- 
    print '@tempValueRow:' + convert(varchar(10),@tempValueRow); 
    print '@cnt:' + convert(varchar(10),@cnt); 
    print''; 
    -------------- 

    set @cnt = @cnt+1; 
END 

idRow बिना संस्करण का उपयोग कर ROW_NUMBER

DECLARE @vTable TABLE (ValueRow int); 
-------Initialize--------- 
insert into @vTable select 345; 
insert into @vTable select 795; 
insert into @vTable select 565; 
--------------------------- 

DECLARE @cnt int = 1; 
DECLARE @max int = (select count(*) from @vTable); 

WHILE @cnt <= @max 
BEGIN 
    DECLARE @tempValueRow int = (
     select ValueRow 
     from (select ValueRow 
      , ROW_NUMBER() OVER(ORDER BY (select 1)) as RowId 
      from @vTable 
     ) T1 
    where t1.RowId = @cnt 
    ); 

    ---work demo---- 
    print '@tempValueRow:' + convert(varchar(10),@tempValueRow); 
    print '@cnt:' + convert(varchar(10),@cnt); 
    print''; 
    -------------- 

    set @cnt = @cnt+1; 
END 
5

मेरे दो सेंट किलोमीटर के जवाब से .., यदि आप एक ड्रॉप करना चाहता हूँ। परिवर्तनीय, आप गिनती के बजाय @RowsToProcess पर उलटी गिनती कर सकते हैं।

DECLARE @RowsToProcess int; 

DECLARE @table1 TABLE (RowID int not null primary key identity(1,1), col1 int) 
INSERT into @table1 (col1) SELECT col1 FROM table2 
SET @RowsToProcess = @@ROWCOUNT 

WHILE @RowsToProcess > 0 -- Countdown 
BEGIN 
    SELECT * 
     FROM @table1 
     WHERE [email protected] 

    --do your thing here-- 

    SET @RowsToProcess = @RowsToProcess - 1; -- Countdown 
END 
+0

स्वीकार्य उत्तर के रूप में यह एक बेहतर समाधान है क्योंकि यह तालिका चर की सामग्री पर निर्भर नहीं है। – beerwin

0

तालिका परिवर्तनीय के माध्यम से संग्रहीत प्रक्रिया लूप के बाद और इसे आरोही ऑर्डर में प्रिंट करता है। यह उदाहरण WHILE लूप का उपयोग कर रहा है।

CREATE PROCEDURE PrintSequenceSeries 
    -- Add the parameters for the stored procedure here 
    @ComaSeperatedSequenceSeries nVarchar(MAX) 
AS 
BEGIN 
    -- SET NOCOUNT ON added to prevent extra result sets from 
    -- interfering with SELECT statements. 
    SET NOCOUNT ON; 

    DECLARE @SERIES_COUNT AS INTEGER 
    SELECT @SERIES_COUNT = COUNT(*) FROM PARSE_COMMA_DELIMITED_INTEGER(@ComaSeperatedSequenceSeries, ',') --- ORDER BY ITEM DESC 

    DECLARE @CURR_COUNT AS INTEGER 
    SET @CURR_COUNT = 1 

    DECLARE @SQL AS NVARCHAR(MAX) 

    WHILE @CURR_COUNT <= @SERIES_COUNT 
    BEGIN 
     SET @SQL = 'SELECT TOP 1 T.* FROM ' + 
      '(SELECT TOP ' + CONVERT(VARCHAR(20), @CURR_COUNT) + ' * FROM PARSE_COMMA_DELIMITED_INTEGER(''' + @ComaSeperatedSequenceSeries + ''' , '','') ORDER BY ITEM ASC) AS T ' + 
      'ORDER BY T.ITEM DESC ' 
     PRINT @SQL 
     EXEC SP_EXECUTESQL @SQL 
     SET @CURR_COUNT = @CURR_COUNT + 1 
    END; 

निम्नलिखित बयान पर क्रियान्वित संग्रहित प्रक्रिया:

EXEC PrintSequenceSeries '11,2,33,14,5,60,17,98,9,10' 

परिणाम एसक्यूएल क्वेरी विंडो में प्रदर्शित नीचे दिखाया गया है:

The Result of PrintSequenceSeries

समारोह PARSE_COMMA_DELIMITED_INTEGER() कि टेबल चर रिटर्न जैसा कि नीचे दिखाया गया है:

CREATE FUNCTION [dbo].[parse_comma_delimited_integer] 
     (
      @LIST  VARCHAR(8000), 
      @DELIMITER VARCHAR(10) = ', 
      ' 
     ) 

     -- TABLE VARIABLE THAT WILL CONTAIN VALUES 
     RETURNS @TABLEVALUES TABLE 
     (
      ITEM INT 
     ) 
     AS 
     BEGIN 
      DECLARE @ITEM VARCHAR(255) 

      /* LOOP OVER THE COMMADELIMITED LIST */ 
      WHILE (DATALENGTH(@LIST) > 0) 
       BEGIN 
        IF CHARINDEX(@DELIMITER,@LIST) > 0 
         BEGIN 
          SELECT @ITEM = SUBSTRING(@LIST,1,(CHARINDEX(@DELIMITER, @LIST)-1)) 
          SELECT @LIST = SUBSTRING(@LIST,(CHARINDEX(@DELIMITER, @LIST) + 
          DATALENGTH(@DELIMITER)),DATALENGTH(@LIST)) 
         END 
        ELSE 
         BEGIN 
          SELECT @ITEM = @LIST 
          SELECT @LIST = NULL 
         END 

        -- INSERT EACH ITEM INTO TEMP TABLE 
        INSERT @TABLEVALUES 
        (
         ITEM 
        ) 
        SELECT ITEM = CONVERT(INT, @ITEM) 
       END 
     RETURN 
     END 
संबंधित मुद्दे

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