কোয়েরিতে ফিরে আসা প্রতিটি সারির জন্য আমি কীভাবে একবার একটি সঞ্চিত প্রক্রিয়া চালাব?


206

আমার কাছে একটি সঞ্চিত প্রক্রিয়া রয়েছে যা নির্দিষ্ট উপায়ে ব্যবহারকারীর ডেটা পরিবর্তন করে। আমি এটি ব্যবহারকারী_আইডি পাস করি এবং এটি জিনিসটি করে। আমি কোনও টেবিলে একটি ক্যোয়ারী চালাতে চাই এবং তারপরে প্রতিটি ব্যবহারকারী_র জন্য আমি সেই ব্যবহারকারী_আইডিতে একবার সঞ্চিত প্রক্রিয়াটি চালিয়ে দেখতে পাই

আমি কীভাবে এর জন্য কোয়েরি লিখব?


5
আপনাকে কী আরডিবিএমএস নির্দিষ্ট করতে হবে - এসকিউএল সার্ভার, ওরাকল,
মাইএসকিউএল

5
সম্ভাবনাগুলি হ'ল আপনার কোনও সঞ্চিত পদ্ধতি দরকার নেই। আপনি কী স্ট্রোকড পদ্ধতিটি "কী" রূপরেখা দিতে পারেন? সম্ভবত পুরো প্রক্রিয়াটি একক আপডেটের বিবৃতি হিসাবে প্রকাশ করা যেতে পারে। যদি সম্ভব হয় তবে "প্রতিটি রেকর্ডের জন্য একবার করুন" প্যাটার্নটি সাধারণত এড়ানো উচিত।
Tomalak

আপনি কোন ডাটাবেস ব্যবহার করছেন?
সুতরাং ব্যবহারকারী

1
আপনার এই নিবন্ধটি পড়তে হবে ... আইটেম 2 বলছে যে কোডার প্রজেক্ট / কেবি / ডেটাবেস / এসকিএলডিওন্ট.এএসপিএক্স ব্যবহার করবে না..মাইন্ড আমি অকাল অপটিমাইজেশনেরও বিরোধী।
মাইকেল প্রেভেকি

7
@ মিশেলপ্রুয়েকি: আপনি যদি এই দুর্বল লিখিত নিবন্ধটিতে আরও পড়েন তবে আপনি দেখতে পাবেন যে আইটেম 10 "সার্ভার সাইড কার্সার ব্যবহার করবেন না যদি না আপনি জানেন যে আপনি কী করছেন" " আমি মনে করি এটি "আমি জানি আমি কী করছি" এর একটি ঘটনা।
গাবে

উত্তর:


246

একটি কার্সার ব্যবহার করুন

যোগ করুন: [এমএস এসকিউএল কার্সার উদাহরণ]

declare @field1 int
declare @field2 int
declare cur CURSOR LOCAL for
    select field1, field2 from sometable where someotherfield is null

open cur

fetch next from cur into @field1, @field2

while @@FETCH_STATUS = 0 BEGIN

    --execute your sproc on each row
    exec uspYourSproc @field1, @field2

    fetch next from cur into @field1, @field2
END

close cur
deallocate cur

এম এস এসকিউএলে, এখানে একটি নিবন্ধ রয়েছে

নোট করুন যে কার্সারগুলি সেট-ভিত্তিক ক্রিয়াকলাপগুলির চেয়ে ধীর, তবে ম্যানুয়ালের তুলনায় দ্রুত হয় - লুপগুলি; এই আরও প্রশ্নে আরও বিশদ

যোগ 2: আপনি যদি কেবল কয়েকটি রেকর্ডের চেয়ে বেশি প্রক্রিয়াজাত করছেন, প্রথমে এগুলিকে একটি টেম্প টেবিলের মধ্যে টানুন এবং টেম্প টেবিলের উপর দিয়ে কার্সার চালান; এটি এসকিউএলকে টেবিল-লকগুলিতে ওঠা এবং অপারেশনকে গতি বাড়ানো থেকে আটকাবে

3 যোগ করুন: এবং অবশ্যই, আপনি যদি প্রতিটি সঞ্চিত পদ্ধতিতে প্রতিটি ব্যবহারকারীর আইডির সাথে আপনার সঞ্চিত পদ্ধতিটি ইনলাইন করতে পারেন এবং পুরো জিনিসটিকে একটি একক এসকিউএল আপডেট বিবৃতি হিসাবে চালাতে পারেন তবে এটি সর্বোত্তম হবে be


21
ঘোষণার পরে আপনি 'ওপেন কার' বাদ দিয়েছিলেন - এটি আমাকে 'কার্সারটি ওপেন নয়' ত্রুটিগুলি দিয়েছিল। আমার কাছে কোনও সম্পাদনা করার মতো প্রতিনিধি নেই।
ফিওনা - myaccessible.website

5
আপনি তাদের মন্তব্য আপ-ভোট দিয়ে ধন্যবাদ জানাতে পারেন। কে জানে, সম্ভবত তারা পরবর্তী বারে সম্পাদনা করার খ্যাতি পাবেন! :-)
রবিনো

নিশ্চিত হয়ে নিন যে আপনি আপনার সঞ্চিত পদ্ধতিতে ব্যবহৃত ক্ষেত্রগুলিতে JOINS এবং WHERE ক্লোজে আপনার সূচকগুলি পরীক্ষা করেছেন। আমি যথাযথ সূচকগুলি যুক্ত করার পরে আমার এসপিকে একটি লুপে কল করে নাটকীয়ভাবে গতিতে থাকি।
ম্যাথু

1
দীর্ঘ সঞ্চালনের ফলে সৃষ্ট সম্ভাব্য লকিং সমস্যা এড়াতে টেম্প টেবিল ব্যবহারের স্মরণ করিয়ে দেওয়ার জন্য ধন্যবাদ।
টনি

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

55

আপনার লুপ প্রয়োজন হলে আপনার পদ্ধতি পরিবর্তন করার চেষ্টা করুন!

প্যারেন্ট সঞ্চিত পদ্ধতির মধ্যে, একটি # টেম্প সারণী তৈরি করুন যাতে আপনার প্রক্রিয়া করা প্রয়োজন এমন ডেটা থাকে। শিশুকে সঞ্চিত পদ্ধতিতে কল করুন, # টিম্প টেবিলটি দৃশ্যমান হবে এবং আপনি এটি প্রক্রিয়া করতে পারেন, আশা করা যায় যে ডেটা সম্পূর্ণ সেট এবং কার্সার বা লুপ ছাড়াই কাজ করে।

এটি সত্যই নির্ভর করে যে এই সন্তানের সঞ্চিত পদ্ধতিটি কী করছে। আপনি যদি আপডেট-ইন হয়ে থাকেন তবে আপনি # টিম টেবিলে যোগদানের "আপডেট হতে" পারেন এবং লুপ ছাড়াই সমস্ত বিবরণ একটি বিবৃতিতে করতে পারেন। INSERT এবং মুছে ফেলার ক্ষেত্রেও এটি করা যেতে পারে। আপনার যদি UPDATE FROMআইএফএসের সাথে একাধিক আপডেট করার প্রয়োজন হয় তবে আপনি সেগুলিকে # টেম্প টেবিলের সাহায্যে একাধিকতে রূপান্তর করতে পারেন এবং CASE বিবৃতি বা যেখানে শর্ত ব্যবহার করতে পারেন।

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

আপনি কোনও লুপে কল করতে চান এই পদ্ধতির সামগ্রীটি পোস্ট করুন, এবং আমি 10 বারের মধ্যে 9 বার বেট করব, আপনি সারিগুলির একটি সেটে কাজ করতে লিখতে পারেন।


3
আপনি খুব ভাল কাজের জন্য +1 ধরে ধরে নিচ্ছেন যে আপনি বাচ্চা স্প্রোককে নিয়ন্ত্রণ করছেন
স্টিভেন এ লো।

কিছুটা ভাবনা করে, এই একাকীকরণটি অনেক বেশি উন্নত!
encc

7
সেট ভিত্তিক ক্রিয়াকলাপ সর্বদা পছন্দসই। যাইহোক, মনে রাখবেন যে একটি এসপি পরিবর্তন করা সর্বদা একটি বিকল্প নয় - মনে করুন বিক্রেতারা সরবরাহ করেছেন সমাধান। কিছু ব্যবহারকারীর এমনকি দৃশ্যমানতা নাও থাকতে পারে, কেবল কার্সর বা লুপ বিকল্পগুলি রেখে। আমার দোকানে, আমাদের ডেভসগুলি সমস্ত কিছু দেখতে পারে তবে বিক্রেতার আবেদনের বাইরে কোনও ট্রিগার, নেস্টেড প্রোকস, রেকর্ডের সংখ্যা হেরফেরে করা ইত্যাদি কারণে কোনও সমাধান তৈরি করা থাকলে তা পরিষ্কার করতে অনেকগুলি বাধা রয়েছে Many অ্যাপ্লিকেশনটির জটিলতা হ'ল কেবল রেকর্ডগুলির মাধ্যমে কার্সার করা।
স্টিভ ম্যাঙ্গামেলি

11

আপনার টেবিল এবং ক্ষেত্রের নামগুলির জন্য এই বিকল্পের মতো কিছু দরকার হবে।

Declare @TableUsers Table (User_ID, MyRowCount Int Identity(1,1)
Declare @i Int, @MaxI Int, @UserID nVarchar(50)

Insert into @TableUser
Select User_ID
From Users 
Where (My Criteria)
Select @MaxI = @@RowCount, @i = 1

While @i <= @MaxI
Begin
Select @UserID = UserID from @TableUsers Where MyRowCount = @i
Exec prMyStoredProc @UserID
Select

 @i = @i + 1, @UserID = null
End

2
লুপগুলি কার্সারের চেয়ে ধীরে ধীরে
স্টিভেন এ। লো


9

আপনি এটি একটি গতিশীল কোয়েরি দিয়ে করতে পারেন।

declare @cadena varchar(max) = ''
select @cadena = @cadena + 'exec spAPI ' + ltrim(id) + ';'
from sysobjects;
exec(@cadena);

6

আপনার সঞ্চিত পদ্ধতিটি যা যা করছে তা অনুলিপি করতে এটি কোনও ব্যবহারকারী-সংজ্ঞায়িত ফাংশন দিয়ে করা যায় না?

SELECT udfMyFunction(user_id), someOtherField, etc FROM MyTable WHERE WhateverCondition

যেখানে udfMyFunction হ'ল এমন একটি ফাংশন যা আপনার ব্যবহারকারীর আইডি লাগে এবং এটির সাথে আপনার যা যা করা দরকার তা করে does

আরও কিছুটা পটভূমির জন্য দেখুন http://www.sqlteam.com/article/user-de- সংজ্ঞায়িত- ফাংশন

আমি সম্মত হই যে যেখানে সম্ভব সেখানে কর্সারগুলি এড়ানো উচিত। এবং এটি সাধারণত সম্ভব!

(অবশ্যই, আমার উত্তরটি অনুমান করে যে আপনি কেবল এসপি থেকে আউটপুট পেতে আগ্রহী এবং আপনি প্রকৃত ডেটা পরিবর্তন করছেন না I আমি মূল প্রশ্ন থেকে "একটি নির্দিষ্ট উপায়ে ব্যবহারকারীর ডেটা পরিবর্তন করে" পাই, তাই ভেবেছি আমি এটি একটি সম্ভাব্য সমাধান হিসাবে উপস্থাপন করব you're আপনি যা করছেন তার উপর নির্ভর করে!)


1
ওপি: "সঞ্চিত পদ্ধতি যা ব্যবহারকারীর ডেটাগুলিকে একটি নির্দিষ্ট উপায়ে পরিবর্তন করে" এমএসডিএন : ব্যবহারকারী-সংজ্ঞায়িত ফাংশনগুলি ডাটাবেস স্থিতিকে সংশোধনকারী ক্রিয়া সম্পাদন করতে ব্যবহার করা যায় না। তবে এসকিউএলএসভিআর 2014 এর সাথে কোনও সমস্যা বলে মনে হচ্ছে না
জননি 5

6

একটি টেবিল পরিবর্তনশীল বা একটি অস্থায়ী টেবিল ব্যবহার করুন।

যেমনটি আগেই উল্লেখ করা হয়েছে, একটি কার্সার একটি শেষ অবলম্বন। বেশিরভাগ কারণ এটি এতে প্রচুর সংস্থান ব্যবহার করে, লকগুলি ইস্যু করে এবং এটি একটি চিহ্ন হতে পারে যা আপনি কীভাবে এসকিউএলকে সঠিকভাবে ব্যবহার করবেন তা বুঝতে পারছেন না।

পার্শ্ব দ্রষ্টব্য: আমি একবারে এমন একটি সমাধান পেয়েছিলাম যা সারণীতে সারিগুলি আপডেট করতে কার্সার ব্যবহার করে। কিছু তদন্তের পরে, এটি প্রমাণিত হয়েছিল যে পুরো জিনিসটি একটি একক আপডেটের কমান্ড দিয়ে প্রতিস্থাপন করা যেতে পারে। যাইহোক, এই ক্ষেত্রে, যেখানে একটি সঞ্চিত পদ্ধতি কার্যকর করা উচিত, একটি একক এসকিউএল-কমান্ড কাজ করবে না।

এর মতো একটি সারণী ভেরিয়েবল তৈরি করুন (আপনি যদি প্রচুর ডেটা নিয়ে কাজ করছেন বা মেমরির স্বল্প হয়ে থাকেন তবে পরিবর্তে একটি অস্থায়ী টেবিল ব্যবহার করুন):

DECLARE @menus AS TABLE (
    id INT IDENTITY(1,1),
    parent NVARCHAR(128),
    child NVARCHAR(128));

idগুরুত্বপূর্ণ।

প্রতিস্থাপন করুন parentএবং childকিছু ভাল ডেটা, উদাহরণস্বরূপ প্রাসঙ্গিক শনাক্তকারী বা ডেটা পুরো সেট চালিত করা সঙ্গে।

সারণীতে ডেটা Inোকান, যেমন:

INSERT INTO @menus (parent, child) 
  VALUES ('Some name',  'Child name');
...
INSERT INTO @menus (parent,child) 
  VALUES ('Some other name', 'Some other child name');

কিছু ভেরিয়েবল ঘোষণা করুন:

DECLARE @id INT = 1;
DECLARE @parentName NVARCHAR(128);
DECLARE @childName NVARCHAR(128);

এবং অবশেষে, টেবিলের ডেটা থেকে কিছুক্ষণ লুপ তৈরি করুন:

WHILE @id IS NOT NULL
BEGIN
    SELECT @parentName = parent,
           @childName = child 
        FROM @menus WHERE id = @id;

    EXEC myProcedure @parent=@parentName, @child=@childName;

    SELECT @id = MIN(id) FROM @menus WHERE id > @id;
END

প্রথম নির্বাচন অস্থায়ী সারণী থেকে ডেটা আনে। দ্বিতীয় নির্বাচন @ID আপডেট করে। MINকোনও সারি নির্বাচন না করা হলে শূন্য ফেরত দেয়।

টেবিলের সারি থাকাকালীন বিকল্প পদ্ধতিটি লুপ করা এবং SELECT TOP 1টেম্প টেবিল থেকে নির্বাচিত সারিটি সরিয়ে ফেলতে হবে:

WHILE EXISTS(SELECT 1 FROM @menuIDs) 
BEGIN
    SELECT TOP 1 @menuID = menuID FROM @menuIDs;

    EXEC myProcedure @menuID=@menuID;

    DELETE FROM @menuIDs WHERE menuID = @menuID;
END;

3

আমি ডেভ রিনকনের গতিশীল ক্যোয়ারী উপায় পছন্দ করি কারণ এটি কার্সার ব্যবহার করে না এবং এটি ছোট এবং সহজ। ভাগ করার জন্য আপনাকে ধন্যবাদ ডেভ

তবে অ্যাজুরে এসকিউএল এবং কোয়েরিতে "স্বতন্ত্র" আমার প্রয়োজনের জন্য, আমাকে কোডটি এইভাবে সংশোধন করতে হয়েছিল:

Declare @SQL nvarchar(max);
-- Set SQL Variable
-- Prepare exec command for each distinctive tenantid found in Machines 
SELECT @SQL = (Select distinct 'exec dbo.sp_S2_Laser_to_cache ' + 
              convert(varchar(8),tenantid) + ';' 
              from Dim_Machine
              where iscurrent = 1
              FOR XML PATH(''))

--for debugging print the sql 
print @SQL;

--execute the generated sql script
exec sp_executesql @SQL;

আমি আশা করি এটা কারো সাহায্যে লাগবে...

আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.