【问题标题】:retrieving all Foreign Keys and their records检索所有外键及其记录
【发布时间】:2013-05-23 12:54:25
【问题描述】:

我想要达到的目标如下。 当我删除一条记录时,我想检查是否有任何 FK 关系并且它需要是递归的。这样我就可以显示与您要删除的记录相关的所有记录的列表。

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

因此,当我尝试删除项目 1 时,我需要先获取您需要删除的项目的列表: 阶段1 区块 1 ....

我想使用带有 ID 和表名(格式 [chema].[tablename])并找到所有这些链接记录的存储过程来执行此操作。

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

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  ' +@eName
        + ' 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

显然您不能嵌套插入执行程序。 但是我真的没有看到任何其他方式来做到这一点。 我已经尝试将其转换为函数,但是还有其他问题,例如动态查询。

任何帮助将不胜感激。

【问题讨论】:

    标签: sql sql-server-2008 recursion nested procedure


    【解决方案1】:

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

    在外部过程中创建一个#results 临时表,然后调用内部过程。

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

    这样您可以节省大量时间,因为您不必移动数据太多。您也不必再嵌套INSERT...EXEC

    您也不再需要dbo.PartialResults 表,因为您可以在动态语句中直接写入#results 表。如果您仍然需要它,为了使递归工作将其替换为您在内部过程中创建的#partialResults 临时表(不要检查是否存在,只需创建新表。有关临时表的说明,请参阅http://sqlity.net/en/1109/temp-tables-scoping-eclipsing/范围界定)。这样每次执行都会创建自己的临时表,您不必处理清理工作。与使用真实桌子相比,这也减轻了一些负担。

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

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

    【讨论】:

    • 感谢塞巴斯蒂安,我会试一试。开始时要简单得多,但我不断添加东西来尝试解决问题。我想我需要一个内部和外部程序,但有点迷失了方向:-)
    • 成功了。我仍然需要额外的#partialResults 临时表来避免无限循环。否则,我会在结果中添加行,遍历结果并在每个循环中为结果添加更多行......这不是最好的想法。无论如何,如果有人对最终代码感兴趣,我会稍后发布,因为我目前没有太多时间。
    猜你喜欢
    • 1970-01-01
    • 2023-03-16
    • 2019-09-18
    • 1970-01-01
    • 2014-12-07
    • 1970-01-01
    • 1970-01-01
    • 2018-10-02
    • 1970-01-01
    相关资源
    最近更新 更多