টি-এসকিউএল: জ্ঞাত মানগুলির একটি অ্যারে দিয়ে লুপিং


90

এখানে আমার পরিস্থিতি:

ধরা যাক আমার একটি সঞ্চিত প্রক্রিয়া রয়েছে যাতে নির্দিষ্ট আইডির একটি সেটে আমাকে অন্য সঞ্চিত পদ্ধতিতে কল করতে হবে; এই কাজ করতে একটি উপায় আছে কি?

অর্থাত্ এটি করার পরিবর্তে:

exec p_MyInnerProcedure 4
exec p_MyInnerProcedure 7
exec p_MyInnerProcedure 12
exec p_MyInnerProcedure 22
exec p_MyInnerProcedure 19

এরকম কিছু করা:

*magic where I specify my list contains 4,7,12,22,19*

DECLARE my_cursor CURSOR FAST_FORWARD FOR
*magic select*

OPEN my_cursor 
FETCH NEXT FROM my_cursor INTO @MyId
WHILE @@FETCH_STATUS = 0
BEGIN

exec p_MyInnerProcedure @MyId

FETCH NEXT FROM my_cursor INTO @MyId
END

আমার মূল লক্ষ্যটি হ'ল রক্ষণাবেক্ষণযোগ্যতা (আইডি এর ব্যবসায়িক পরিবর্তন হিসাবে সরানো / যুক্ত করা সহজ), সমস্ত আইডির একক লাইনে তালিকা তৈরি করতে সক্ষম হওয়া ... পারফরম্যান্স কোনও সমস্যার চেয়ে বড় হওয়া উচিত নয়


: যদি আপনি varchars, কার্সার সঙ্গে সমাধান মত একটি অ-পূর্ণসংখ্যা তালিকায় পুনরুক্তি করতে প্রয়োজন, সম্পর্কিত বলছি মাধ্যমে-এ-তালিকা অফ স্ট্রিং-ইন-SQL সার্ভার
Pac0

উত্তর:


105
declare @ids table(idx int identity(1,1), id int)

insert into @ids (id)
    select 4 union
    select 7 union
    select 12 union
    select 22 union
    select 19

declare @i int
declare @cnt int

select @i = min(idx) - 1, @cnt = max(idx) from @ids

while @i < @cnt
begin
     select @i = @i + 1

     declare @id = select id from @ids where idx = @i

     exec p_MyInnerProcedure @id
end

আমি আশা করছিলাম যে এখানে আরও মার্জিত উপায় হবে তবে আমি মনে করি এটি যতটা কাছে আসবে ততই কাছাকাছি হবে: এখানে নির্বাচন / ইউনিয়ন এবং উদাহরণটি থেকে কার্সার ব্যবহারের মধ্যে একটি সংকর ব্যবহার করে শেষ হয়েছিল। ধন্যবাদ!
জন

13
@ জোহান: আপনি যদি ২০০৮ ব্যবহার করছেন তবে আপনি INSERT @ID VALUES (4), (7), (12), (22), (19)
পিটার রডোচিয়া

4
শুধু এফওয়াইআই, এর মতো মেমরি টেবিলগুলি কার্সারের চেয়ে সাধারণত দ্রুত হয় (যদিও 5 টি মানের জন্য আমি খুব কমই দেখতে পাচ্ছি যে কোনও পার্থক্য তৈরি করছে), তবে আমি তাদের পছন্দ করার সবচেয়ে বড় কারণটি হ'ল আমি অ্যাপ্লিকেশন কোডটিতে যা খুঁজে পেয়েছি তার অনুরূপ বাক্য গঠন খুঁজে পেয়েছি , যেখানে কার্সারগুলি অপেক্ষাকৃত পৃথক বলে মনে হয় (আমার কাছে)।
অ্যাডাম রবিনসন

যদিও এটি অনুশীলনে ক্ষতিপূরণটি খুব সামান্যই ক্ষতিগ্রস্থ করবে আমি উল্লেখ করতে চাই যে এটি নির্ধারিত স্থানের মধ্যে সমস্ত সংখ্যার মাধ্যমে পুনরাবৃত্তি করে। উপস্থিত থাকার সাথে নীচের সমাধানটি (@ আইডিস থেকে * নির্বাচন করুন) ... লজিক্যালি আরও সাউন্ড (এবং আরও মার্জিত)।
ডের ইউ

41

এই দৃশ্যে আমি যা করি তা হ'ল আইডিগুলি ধরে রাখতে একটি টেবিল ভেরিয়েবল তৈরি করা।

  Declare @Ids Table (id integer primary Key not null)
  Insert @Ids(id) values (4),(7),(12),(22),(19)

- (বা এই টেবিলটি তৈরি করতে অন্য টেবিলের মূল্যবান ফাংশনটি কল করুন)

তারপরে এই টেবিলের সারিগুলির উপর ভিত্তি করে লুপ

  Declare @Id Integer
  While exists (Select * From @Ids)
    Begin
      Select @Id = Min(id) from @Ids
      exec p_MyInnerProcedure @Id 
      Delete from @Ids Where id = @Id
    End

বা ...

  Declare @Id Integer = 0 -- assuming all Ids are > 0
  While exists (Select * From @Ids
                where id > @Id)
    Begin
      Select @Id = Min(id) 
      from @Ids Where id > @Id
      exec p_MyInnerProcedure @Id 
    End

উপরের দুটি পদ্ধতির একটি কার্সারের চেয়ে অনেক দ্রুত (নিয়মিত ব্যবহারকারীর সারণী (গুলি) এর বিপরীতে ঘোষিত)। সারণী-মূল্যবান ভেরিয়েবলগুলির একটি খারাপ রেপ রয়েছে কারণ যখন সঠিকভাবে ব্যবহার করা হয় না (সারিগুলির বৃহত সংখ্যক বিস্তৃত টেবিলগুলির জন্য) তারা পারফর্মেন্ট হয় না। তবে আপনি যদি এগুলি কেবল কোনও মূল মান বা 4 বাইট পূর্ণসংখ্যা ধরে রাখতে ব্যবহার করেন তবে একটি সূচক সহ (এই ক্ষেত্রে যেমন) তারা অত্যন্ত দ্রুত।


উপরের পদ্ধতির সারণী ভেরিয়েবলে ঘোষিত কার্সারের সমান বা ধীর। এটি অবশ্যই দ্রুত নয়। যদিও এটি নিয়মিত ব্যবহারকারীর টেবিলগুলিতে কার্সার হিসাবে ডাব্লু / ডিফল্ট বিকল্প হিসাবে ঘোষিত হয় তার চেয়ে দ্রুত হবে।
পিটার রডোচিয়া 15

@ পিটার, আহ, হ্যাঁ আপনি সঠিক, আমি ভুলভাবে ধরে নিয়েছি যে কার্সার ব্যবহারের ফলে একটি নিয়মিত ব্যবহারকারীর টেবিল বোঝানো হয়, কোনও টেবিলের চলক নয় .. পার্থক্য পরিষ্কার করার জন্য সম্পাদনা করা হয়েছে
চার্লস ব্রেটানা

16

একটি স্ট্যাটিক কার্সার ভেরিয়েবল এবং একটি বিভক্ত ফাংশন ব্যবহার করুন :

declare @comma_delimited_list varchar(4000)
set @comma_delimited_list = '4,7,12,22,19'

declare @cursor cursor
set @cursor = cursor static for 
  select convert(int, Value) as Id from dbo.Split(@comma_delimited_list) a

declare @id int
open @cursor
while 1=1 begin
  fetch next from @cursor into @id
  if @@fetch_status <> 0 break
  ....do something....
end
-- not strictly necessary w/ cursor variables since they will go out of scope like a normal var
close @cursor
deallocate @cursor

ডিফল্ট বিকল্পগুলির ব্যবহারকারীর টেবিলগুলির বিপরীতে ঘোষিত হওয়ার পরে কার্সারগুলির একটি খারাপ প্রতিক্রিয়া থাকে কারণ প্রচুর ওভারহেড তৈরি করতে পারে।

তবে এই ক্ষেত্রে ওভারহেড বেশ ন্যূনতম, এখানে অন্য কোনও পদ্ধতির চেয়ে কম than স্ট্যাটিক এসকিউএল সার্ভারকে টেম্পিডবিতে ফলাফলগুলি কার্যকর করতে এবং তারপরে পুনরাবৃত্তি করতে বলে। এর মতো ছোট তালিকার জন্য এটি সর্বোত্তম সমাধান।


7

আপনি নীচের মত চেষ্টা করতে পারেন:

declare @list varchar(MAX), @i int
select @i=0, @list ='4,7,12,22,19,'

while( @i < LEN(@list))
begin
    declare @item varchar(MAX)
    SELECT  @item = SUBSTRING(@list,  @i,CHARINDEX(',',@list,@i)-@i)
    select @item

     --do your stuff here with @item 
     exec p_MyInnerProcedure @item 

    set @i = CHARINDEX(',',@list,@i)+1
    if(@i = 0) set @i = LEN(@list) 
end

6
আমি সেই তালিকাটির ঘোষণাটি এর মতো করে দেব: @list ='4,7,12,22,19' + ','- সুতরাং এটি সম্পূর্ণ পরিষ্কার যে তালিকাটি কমা দিয়ে শেষ করতে হবে (এটি এটি ছাড়া কাজ করে না!)।
আজভি জেসি

5

আমি সাধারণত নিম্নলিখিত পদ্ধতিটি ব্যবহার করি

DECLARE @calls TABLE (
    id INT IDENTITY(1,1)
    ,parameter INT
    )

INSERT INTO @calls
select parameter from some_table where some_condition -- here you populate your parameters

declare @i int
declare @n int
declare @myId int
select @i = min(id), @n = max(id) from @calls
while @i <= @n
begin
    select 
        @myId = parameter
    from 
        @calls
    where id = @i

        EXECUTE p_MyInnerProcedure @myId
    set @i = @i+1
end

2
CREATE TABLE #ListOfIDs (IDValue INT)

DECLARE @IDs VARCHAR(50), @ID VARCHAR(5)
SET @IDs = @OriginalListOfIDs + ','

WHILE LEN(@IDs) > 1
BEGIN
SET @ID = SUBSTRING(@IDs, 0, CHARINDEX(',', @IDs));
INSERT INTO #ListOfIDs (IDValue) VALUES(@ID);
SET @IDs = REPLACE(',' + @IDs, ',' + @ID + ',', '')
END

SELECT * 
FROM #ListOfIDs

0

পদ্ধতিগত প্রোগ্রামিং ভাষা (এখানে পাইথন) ব্যবহার করে আপনার ডিবির সাথে সংযোগ স্থাপন করুন এবং সেখানে লুপটি করুন। এইভাবে আপনি জটিল লুপগুলিও করতে পারেন।

# make a connection to your db
import pyodbc
conn = pyodbc.connect('''
                        Driver={ODBC Driver 13 for SQL Server};
                        Server=serverName;
                        Database=DBname;
                        UID=userName;
                        PWD=password;
                      ''')
cursor = conn.cursor()

# run sql code
for id in [4, 7, 12, 22, 19]:
  cursor.execute('''
    exec p_MyInnerProcedure {}
  '''.format(id))
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.