2010-06-28 24 views
9

İşte ben VBScript Subroutine:SQL Server'da yinelemeli olarak adlandırılan saklı yordam mümkün mü?

sub buildChildAdminStringHierarchical(byval pAdminID, byref adminString) 
    set rsx = conn.execute ("select admin_id from administrator_owners where admin_id not in (" & adminString & ") and owner_id = " & pAdminID) 

    do while not rsx.eof 
     adminString = adminString & "," & rsx(0) 
     call buildChildAdminStringHierarchical(rsx(0),adminString) 
     rsx.movenext 
    loop 
end sub 

Altprogramda yinelemeli çağrı var olduğundan bunu saklı bir prosedüre dönüştürmek için var mı?

Denediğim şey ...

CREATE PROCEDURE usp_build_child_admin_string_hierarchically 
    @ID AS INT, 
    @ADMIN_STRING AS VARCHAR(8000), 
    @ID_STRING AS VARCHAR(8000) OUTPUT 
AS 
BEGIN 
    -- SET NOCOUNT ON added to prevent extra result sets from 
    -- interfering with SELECT statements. 
    SET NOCOUNT ON; 

    DECLARE @index int; 
    DECLARE @length int; 
    DECLARE @admin_id int; 
    DECLARE @new_string varchar(8000); 

    SET @index = 1; 
    SET @length = 0; 
    SET @new_string = @ADMIN_STRING; 

    CREATE TABLE #Temp (ID int) 

    WHILE @index <= LEN(@new_string) 
    BEGIN 
     IF CHARINDEX(',', @new_string, @index) = 0 
      SELECT @length = (LEN(@new_string) + 1) - @index; 
     ELSE 
      SELECT @length = (CHARINDEX(',', @new_string, @index) - @index); 
     SELECT @admin_id = CONVERT(INT,SUBSTRING(@new_string, @index, @length)); 
     SET @index = @index + @length + 1; 
     INSERT INTO #temp VALUES(@admin_id); 
    END 

    DECLARE TableCursor CURSOR FOR 
     SELECT Admin_ID FROM Administrator_Owners WHERE Admin_ID NOT IN (SELECT ID FROM #temp) AND Owner_ID = @ID; 

    OPEN TableCursor; 
    FETCH NEXT FROM TableCursor INTO @admin_id; 

    WHILE @@FETCH_STATUS = 0 
    BEGIN 
     IF LEN(@ID_STRING) > 0 
     SET @ID_STRING = @ID_STRING + ',' + CONVERT(VARCHAR, @admin_id); 
     ELSE 
     SET @ID_STRING = CONVERT(VARCHAR, @admin_id); 

     EXEC usp_build_child_admin_string_hierarchically @admin_id, @ID_STRING, @ID_STRING; 

     FETCH NEXT FROM TableCursor INTO @admin_id; 
    END 

    CLOSE TableCursor; 
    DEALLOCATE TableCursor; 

    DROP TABLE #temp; 
END 
GO 

Ancak saklı yordam çağrıldığında şu hatayı alıyorum ... 'TableCursor' aynı adı taşıyan bir imleç zaten var.

+3

Sorunun yanıtı, "TableCursor" imleç kapatılmadan önce yapıldığı için hata oluştuğunu tahmin ediyorum. İmlecin dinamik bir isim vermesi mümkün olabilir (belki de 'TableCursorN', N yinelemenin derinliği - bunu ekstra bir parametre olarak yapmanız gerekir)? – FrustratedWithFormsDesigner

+2

Sorun, kesinlikle izin verilen özyineleme değil (http://msdn.microsoft.com/en-us/library/aa175801(SQL.80).aspx), bir statik imleç adı kullanıyorsunuz. MS SQL Server'daki imleçler hakkında bunu bir cevap olarak göndermeye yetecek kadar bir şey bilmiyorum, çünkü bu durumda imlecin nasıl kullanılacağını söylemek yararlı olacaktır! :-) –

cevap

7

Sorun, imleciniz global olmasa da, 'un bir oturum imleci olan olmasıdır. Yineleme yaptığınız için, her bir yineleme yeni bir imleçte bir imleç yaratıyor olsa da, hepsi aynı anda aynı PID'de (bağlantı) oluşturulmaktadır, dolayısıyla çarpışmadır.

Özyineleme sırasında çoğaltılamayacak bazı ölçütlere dayanarak, yordamın her yinelemesinde benzersiz imleç adlarını oluşturmanız gerekir. Veya tercihen set mantığını kullanarak ihtiyacınız olanı yapmak için bir yol bulun ve özyinelemeli bir CTE kullanarak gerekli özyineyi işleyin.

+3

Benzersiz imleç isimleri oluşturmanın en iyi yolu nedir? Dinamik sql ile çok iyi değilim. – Ryan

2

Bunu yapabilirsiniz, ancak genellikle iyi bir fikir değildir. SQL set tabanlı işlemler için yapılır. Ayrıca, MS SQL Server'da en azından, özyineleme yapabildiği yinelemeli çağrıların sayısıyla sınırlıdır. Sadece 32 seviyeye kadar derinlerde yuva yapabilirsiniz.

Durumunuzdaki sorun, CURSOR'un her bir aramada sürmesidir, bu yüzden bir kereden fazla oluşturmayı bitirdiniz.

34

Böyle bir LOCAL imleci belirtebilirsiniz:

DECLARE TableCursor CURSOR LOCAL FOR 
SELECT ... 

En azından SQL Server 2008 R2 (benim makine), bu özyinelemeli hataları "İmleç zaten var" içine çalıştırmadan sproc olabilmesinin önünü içinde .

+2

Bu sorun benim çok fazla sorun çözdü Blorgbeard – Javier

+4

Bunun 2005 için de çalıştığını teyit ederim. http://msdn.microsoft.com/en-us/library/ms180169(v=sql.90).aspx Bu cevap doğru olarak işaretlenmelidir. –

+1

Tekrar doğrulandı –

İlgili konular