استخدام المؤشر مع SQL الديناميكي في إجراء مخزن
-
20-08-2019 - |
سؤال
لدي عبارة SQL ديناميكية قمت بإنشائها في إجراء مخزن.أحتاج إلى تكرار النتائج باستخدام المؤشر.أواجه صعوبة في معرفة بناء الجملة الصحيح.هذا ما أفعله.
SELECT @SQLStatement = 'SELECT userId FROM users'
DECLARE @UserId
DECLARE users_cursor CURSOR FOR
EXECUTE @SQLStatment --Fails here. Doesn't like this
OPEN users_cursor
FETCH NEXT FROM users_cursor
INTO @UserId
WHILE @@FETCH_STATUS = 0
BEGIN
EXEC asp_DoSomethingStoredProc @UserId
END
CLOSE users_cursor
DEALLOCATE users_cursor
ما هي الطريقة الصحيحة للقيام بذلك؟
المحلول
وA المؤشر لن يقبل إلا بيانا حدد، لذلك إذا كان SQL تحتاج حقا أن تكون ديناميكية جعل جزء تعلن المؤشر البيان يتم تنفيذ. لأدناه للعمل الخادم الخاص بك سيكون لديك لتكون باستخدام المؤشرات العالمية.
Declare @UserID varchar(100)
declare @sqlstatement nvarchar(4000)
--move declare cursor into sql to be executed
set @sqlstatement = 'Declare users_cursor CURSOR FOR SELECT userId FROM users'
exec sp_executesql @sqlstatement
OPEN users_cursor
FETCH NEXT FROM users_cursor
INTO @UserId
WHILE @@FETCH_STATUS = 0
BEGIN
Print @UserID
EXEC asp_DoSomethingStoredProc @UserId
FETCH NEXT FROM users_cursor --have to fetch again within loop
INTO @UserId
END
CLOSE users_cursor
DEALLOCATE users_cursor
إذا كنت بحاجة إلى تجنب استخدام المؤشرات العالمية، التي يمكن أيضا إدراج نتائج SQL ديناميكي في جدول مؤقت، ومن ثم استخدام هذا الجدول لتعبئة المؤشر.
Declare @UserID varchar(100)
create table #users (UserID varchar(100))
declare @sqlstatement nvarchar(4000)
set @sqlstatement = 'Insert into #users (userID) SELECT userId FROM users'
exec(@sqlstatement)
declare users_cursor cursor for Select UserId from #Users
OPEN users_cursor
FETCH NEXT FROM users_cursor
INTO @UserId
WHILE @@FETCH_STATUS = 0
BEGIN
EXEC asp_DoSomethingStoredProc @UserId
FETCH NEXT FROM users_cursor
INTO @UserId
END
CLOSE users_cursor
DEALLOCATE users_cursor
drop table #users
نصائح أخرى
وهذا الرمز هو مثال جيد جدا لعمود ديناميكية مع المؤشر، لأنك لا تستطيع استخدام '+' فيSTATEMENT:
ALTER PROCEDURE dbo.spTEST
AS
SET NOCOUNT ON
DECLARE @query NVARCHAR(4000) = N'' --DATA FILTER
DECLARE @inputList NVARCHAR(4000) = ''
DECLARE @field sysname = '' --COLUMN NAME
DECLARE @my_cur CURSOR
EXECUTE SP_EXECUTESQL
N'SET @my_cur = CURSOR FAST_FORWARD FOR
SELECT
CASE @field
WHEN ''fn'' then fn
WHEN ''n_family_name'' then n_family_name
END
FROM
dbo.vCard
WHERE
CASE @field
WHEN ''fn'' then fn
WHEN ''n_family_name'' then n_family_name
END
LIKE ''%''+@query+''%'';
OPEN @my_cur;',
N'@field sysname, @query NVARCHAR(4000), @my_cur CURSOR OUTPUT',
@field = @field,
@query = @query,
@my_cur = @my_cur OUTPUT
FETCH NEXT FROM @my_cur INTO @inputList
WHILE @@FETCH_STATUS = 0
BEGIN
PRINT @inputList
FETCH NEXT FROM @my_cur INTO @inputList
END
RETURN
العمل مع قاعدة بيانات غير العلائقية (IDMS أي شخص؟) عبر اتصال ODBC يوصف بأنه واحد من تلك الأوقات حيث المؤشرات وSQL ديناميكية يبدو أن الطريق الوحيد.
select * from a where a=1 and b in (1,2)
ويأخذ 45 دقيقة للرد بينما أعيدت كتابتها لاستخدام keysets دون في البند سيتم تشغيل في أقل من 1 ثانية:
select * from a where (a=1 and b=1)
union all
select * from a where (a=1 and b=2)
وإذا كان في بيان للعمود B يحتوي على 1145 الصفوف، وذلك باستخدام المؤشر إلى إنشاء عبارات indidivudal وتنفيذها كما SQL الديناميكي هو أسرع بكثير من استخدام في البند. سخيفة يا؟
ونعم، ليس هناك وقت في قاعدة بيانات علائقية التي يجب أن تستخدم في المؤشر. أنا فقط لا يمكن أن أصدق أنني قد وصلنا عبر مثيل حيث حلقة المؤشر هي عدة مقادير أسرع.
أولا، تجنب استخدام المؤشر إذا كان ذلك ممكنا. وفيما يلي بعض الموارد لاستئصال بها عندما يبدو أنك لا يمكن الاستغناء عنها:
يجب أن يكون هناك 15 طرق لانقاص والمؤشرات الخاصة بك ... جزء 1، مقدمة
تجهيز صف على حدة الصف بدون المؤشر
وقال ذلك، على الرغم من أنك قد تكون عالقة مع واحدة بعد كل شيء - أنا لا أعرف ما يكفي من سؤالك للتأكد من أن أي من تلك تطبيق. إذا كان هذا هو الحال، كنت قد حصلت مشكلة مختلفة - يجب أن تكون العبارة حدد المؤشر لعلامة <م> الفعلي م> عبارة SELECT، وليس عبارة EXECUTE. كنت عالقا.
ولكن انظر جواب من cmsjr (والذي جاء في حين كنت أكتب) حول استخدام جدول مؤقت. وأود أن تجنب العالمي م> المؤشرات أكثر من "سهل" منها ....
بعد التبديل مؤخرًا من Oracle إلى SQL Server (تفضيل صاحب العمل)، لاحظت أن دعم المؤشر في SQL Server متأخر.المؤشرات ليست دائما شريرة، وأحيانا تكون مطلوبة، وأحيانا أسرع بكثير، وأحيانا أكثر نظافة من محاولة ضبط استعلام معقد عن طريق إعادة ترتيب أو إضافة تلميحات التحسين.يعتبر الرأي "المؤشرات شريرة" أكثر بروزًا في مجتمع SQL Server.
لذلك أعتقد أن هذه الإجابة هي التبديل إلى Oracle أو إعطاء MS دليلاً.
- أوراكل تنفيذ فوري في المؤشر
- حلقة من خلال مؤشر ضمني (أ
for
حلقة ضمنا يحدد/يفتح/يغلق المؤشر!)
وهناك مثال آخر وهو أود أن أشاطركم صور: D http://www.sommarskog.se/dynamic_sql.html#cursor0
وثمة خيار آخر في SQL Server هو أن تفعل كل الاستعلام عن الدينامية الخاصة بك إلى متغير جدول في بروك المخزنة، ثم استخدام مؤشر الاستعلام ومعالجة ذلك. كما أن النقاش المؤشر اللعين :)، لقد رأيت دراسات تبين أن في بعض الحالات، مؤشر يمكن أن يكون في الواقع أسرع إذا صحيح إعداد. أنا استخدامها نفسي عندما الاستعلام المطلوب هو معقد جدا، أو فقط لا إنسانيا (بالنسبة لي؛).) ممكن
وهذا الرمز يمكن أن تكون مفيدة بالنسبة لك.
ومثال على استخدام المؤشر في خادم SQL
DECLARE sampleCursor CURSOR FOR
SELECT K.Id FROM TableA K WHERE ....;
OPEN sampleCursor
FETCH NEXT FROM sampleCursor INTO @Id
WHILE @@FETCH_STATUS <> -1
BEGIN
UPDATE TableB
SET
...