2013-05-28 74 views
0

我试图实现的是以下内容。 当我删除一条记录时,我想检查是否有任何FK关系,并且它需要递归。这样我可以显示与您想要删除的记录相关的所有记录的列表。检索所有外键及其记录

所以嵌套链接的一个小例子 项目1 - >第1阶段 - >块1 - > ..

所以,当我尝试删除项目1我要得到你需要的物品清单删除第一: 阶段1 块1 ....

我想与一个存储过程,需要一个ID和一个表名(格式[CHEMA] [表名]),发现所有这些链接的记录要做到这一点。

我遇到的问题是递归部分。 这里是我到目前为止的代码:

ALTER PROCEDURE core.usp_CanBeDeleted  
    @entityId int, 
    @entityName nvarchar(250) 
AS 
BEGIN 
    DECLARE @NumberRecords int, @RowCount int 
    DECLARE @childId int 
    DECLARE @query nvarchar(max) 
    DECLARE @eName nvarchar(250) , @keyName nvarchar(250) 
    DECLARE @columnName nvarchar(250) 

    DECLARE @keys TABLE(
     RowID int IDENTITY(1, 1), 
     name nvarchar(250), 
     entityName nvarchar(250), 
     columnName nvarchar(250) 
    ) 

    if not exists (select * from sysobjects where name='partialResults' and xtype='U') 
    BEGIN 
     CREATE TABLE partialResults(
      RowID int IDENTITY(1, 1), 
      id int, 
      parentId int, 
      name nvarchar(250), 
      FK_name nvarchar(250) 
     ) 
    END 

    DECLARE @recusiveResults TABLE(
     RowID int, 
     id int, 
     parentId int, 
     name nvarchar(250), 
     FK_name nvarchar(250) 
    ) 

    DECLARE @results TABLE(
     RowID int, 
     id int, 
     parentId int, 
     name nvarchar(250), 
     FK_name nvarchar(250) 
    ) 

    SET @RowCount = 1 

     -- get all FK's of the entity 
    INSERT INTO @keys 
    SELECT name, '[' + OBJECT_SCHEMA_NAME(parent_object_id) + '].[' +  OBJECT_NAME(parent_object_id)+ ']',cu.column_name 
    from sys.foreign_keys k 
    INNER JOIN INFORMATION_SCHEMA.KEY_COLUMN_USAGE CU 
    ON k.name = CU.CONSTRAINT_NAME 
    where k.referenced_object_id = OBJECT_ID(@entityName) 

    -- set variable to number of records in temp table 
    SET @NumberRecords = @@ROWCOUNT 

    -- loop through the FK's an get all linked entities 
    WHILE(@RowCount <= @NumberRecords) 
    BEGIN 

     SELECT @keyName = name, @eName = entityName, @columnName = columnName 
     FROM @keys 
     WHERE RowId = @RowCount 

     -- get all FK information 
     SET @query = 'INSERT INTO partialResults(FK_name, name, id, parentId)' 
     + ' SELECT ''' + @keyName + ''','''+ @eName + ''',' + 'id,' +   cast(@entityId as varchar(25)) + ' as parentid' 
     + ' FROM ' [email protected] 
     + ' WHERE id in ' 
     + ' (SELECT ' + @columnName 
      + ' FROM ' + @entityName 
      + ' WHERE id = ' + cast(@entityId as varchar(25)) 
      + ')' 

     --print @query            
     EXEC (@query) 

     SET @RowCount = @RowCount + 1 
    END 

    -- rest number of records 
    SET @RowCount = 1 
    SELECT @NumberRecords = count(id) 
    FROM partialResults 

    -- save partialResults 
    INSERT INTO @results--(FK_name, name, id, parentId) 
    SELECT *--FK_name, name, id, parentId 
    FROM partialResults 

    DELETE FROM partialResults 

    WHILE(@RowCount <= @NumberRecords) 
     BEGIN 
     -- select next row 
     SELECT @childId = id, @eName = name 
     FROM @results 
     WHERE RowId = @RowCount         

     INSERT INTO @recusiveResults   
     EXEC core.usp_CanBeDeleted @childId, @eName 

     SET @RowCount = @RowCount + 1 
    END 

    INSERT INTO @results 
    SELECT * 
    FROM @recusiveResults 

    if exists (select * from sysobjects where name='partialResults' and xtype='U') 
    BEGIN 
     -- remove temp tables 
     DROP TABLE partialResults 
    END 
    -- return results 
    SELECT * 
    FROM @results  
END 
GO 

问题就出在这里:

INSERT INTO @recusiveResults   
EXEC core.usp_CanBeDeleted @childId, @eName 

Apparantly不能嵌套插入EXEC。然而,我真的没有看到任何其他的方式来做到这一点。 我试过把它转换成一个函数,但后来还有其他问题,如动态查询。

任何帮助将大大apreciated。

回答

1

将程序拆分为外部程序和内部程序。

在外层过程中创建#results temp-table,然后调用内层过程。

在内部程序中放入包括递归在内的所有逻辑,但不是在最后选择结果,而是将结果插入已存在的#results表中。

这样你就安全了很多时间,因为你不必移动数据。你也不必再嵌套INSERT...EXEC了。

您也不需要dbo.PartialResults表,因为您可以直接写入动态语句中的#results表。如果你仍然需要它,为了使递归工作取而代之的是你在内部过程中创建的#partialResults临时表(不要检查是否存在,只需创建一个新表。请参阅http://sqlity.net/en/1109/temp-tables-scoping-eclipsing/了解临时表范围的解释) 。这样,每次执行都创建自己的临时表,并且不必处理清理。与使用真实表格相比,这也不那么沉重。

最后,所有的表变量也可以。

在内部程序结束后,您可以执行一个简单的SELECT * FROM #results;来输出所有收集的结果。

+0

谢谢塞巴斯蒂安,我会试试看。 开始了很简单,但我不断增加的东西来尝试和解决问题。 我想我会需要一个内部和外部程序,但有点失去了我的方式:-) –

+0

它的工作。我仍然需要额外的#partialResults临时表来避免无限循环。 否则,我会将结果添加到结果中,循环播放结果并在每个循环中添加更多结果到结果......这不会是最好的想法。 无论如何,如果有人对最终代码感兴趣,我会在稍后发布,因为我现在没有太多时间。 –

相关问题