AskOverflow.Dev

AskOverflow.Dev Logo AskOverflow.Dev Logo

AskOverflow.Dev Navigation

  • 主页
  • 系统&网络
  • Ubuntu
  • Unix
  • DBA
  • Computer
  • Coding
  • LangChain

Mobile menu

Close
  • 主页
  • 系统&网络
    • 最新
    • 热门
    • 标签
  • Ubuntu
    • 最新
    • 热门
    • 标签
  • Unix
    • 最新
    • 标签
  • DBA
    • 最新
    • 标签
  • Computer
    • 最新
    • 标签
  • Coding
    • 最新
    • 标签
主页 / dba / 问题 / 205717
Accepted
skeletank
skeletank
Asked: 2018-05-04 08:20:02 +0800 CST2018-05-04 08:20:02 +0800 CST 2018-05-04 08:20:02 +0800 CST

使用模式绑定更改视图时脚本删除/创建依赖项

  • 772

在 SQL Server 2017 中,我有一个视图“ParentView”,它被其他视图“ChildView1”、“ChildView2”等引用。这些视图被其他视图“GrandChildView1”、“GrandChildView2”等引用,等等向前。我确保将所有视图设置为具有“WITH SCHEMABINDING”。当我想更改“ParentView”时,我需要删除并创建所有相关视图。当然,这非常有意义,因为我启用了“WITH SCHEMABINDING”,并且我可能会做出可能破坏其中一个依赖视图的更改。然而,通过用户界面做所有这些是乏味的,所以我想知道......

我怎样才能获得一个将视图或任何对象作为输入并根据依赖关系创建删除/创建语句的脚本?

例如:

DROP VIEW [dbo].[GrandChild]
GO
DROP VIEW [dbo].[Child]
GO
ALTER VIEW [dbo].[Parent]
...
GO
CREATE VIEW [dbo].[Child]
...
GO
CREATE VIEW [dbo].[GrandChild]
...
GO

笔记

  • 这不必特定于视图。我也有依赖函数和存储过程。
  • 我的观点都不是索引视图。
sql-server sql-server-2017
  • 1 1 个回答
  • 619 Views

1 个回答

  • Voted
  1. Best Answer
    skeletank
    2018-05-04T11:54:18+08:002018-05-04T11:54:18+08:00

    我找到了一种通过使用几个不同的脚本来执行此操作的方法。

    首先,我需要设置来自 Greg M. Lucas 的“PrintString”存储过程,以便打印我的所有语句而不截断它们。

    CREATE PROCEDURE [dbo].[PrintString]
    (
      @InputString     nvarchar(max)  = NULL
    , @MaxPrintLength  int            = 4000
    )
    AS
    BEGIN
        SET NOCOUNT ON
        --! CONSTANTS (keep it SQL2005 compatible)
        DECLARE @LF          char ( 1 ); SET @LF         = CHAR(10);
        DECLARE @CR          char ( 1 ); SET @CR         = CHAR(13);
        DECLARE @CRLF        char ( 2 ); SET @CRLF       = CHAR(13) + CHAR(10);
        DECLARE @LINE_BREAK  char ( 3 ); SET @LINE_BREAK = '%' + @LF + '%';
        --! Working Values
        DECLARE @WorkingLength    bigint
        DECLARE @WorkingString    nvarchar  (  max )
        DECLARE @SubString        nvarchar  (  max )
        DECLARE @SubStringLength  bigint
        --! Validate/correct inputs
        SET @MaxPrintLength = COALESCE(NULLIF(@MaxPrintLength, 0), 4000)
        IF @MaxPrintLength > 4000
            BEGIN
                RAISERROR('The @MaxPrintLength value of %d is greater than the maximum length supported by PRINT for nvarchar strings (4000)', 17, 1, @MaxPrintLength);
                RETURN(60000);
            END
        --! Working variables
        DECLARE @InputLength bigint = LEN(@InputString)
        IF @InputLength = 0
            GOTO OnComplete;
        --!
        --! Our input string may contain either carriage returns, line feeds or both
        --! to separate printing lines so we need to standardise on one of these (LF)
        --!
        SET @WorkingString = REPLACE(REPLACE(@InputString, @CRLF, @LF), @CR, @LF);
        --!
        --! If there are line feeds we use those to break down the text
        --! into individual printed lines, otherwise we print it in
        --! bite-size chunks suitable for consumption by PRINT
        --!
        IF PATINDEX(@LINE_BREAK, @InputString) > 0
            BEGIN --[BREAK_BY_LINE_FEED]
                --! Add a line feed on the end so the final iteration works as expected
                SET @WorkingString  = @WorkingString + @LF;
                SET @WorkingLength  = LEN(@WorkingString);
                DECLARE @LineFeedPos    bigint    = 0
                WHILE @WorkingLength > 0
                    BEGIN
                        --!
                        --! Get the position of the next line feed
                        --!
                        SET @LineFeedPos = PATINDEX(@LINE_BREAK, @WorkingString);
                        IF @LineFeedPos > 0
                            BEGIN
                                SET @SubString        = SUBSTRING(@WorkingString, 1, @LineFeedPos - 1);
                                SET @SubStringLength  = LEN(@SubString);
                                --!
                                --! If this string is too long for a single PRINT, we pass it back
                                --! to PrintString which will process the string in suitably sized chunks
                                --!
                                IF LEN(@SubString) > @MaxPrintLength
                                    EXEC [PrintString] @InputString = @SubString
                                ELSE
                                    PRINT @SubString;
                                --! Remove the text we've just processed
                                SET @WorkingLength    = @WorkingLength - @LineFeedPos;
                                SET @WorkingString    = SUBSTRING(@WorkingString, @LineFeedPos + 1, @WorkingLength);
                            END
                    END
            END --[BREAK_BY_LINE_FEED]
        ELSE
            BEGIN --[BREAK_BY_LENGTH]
                --!
                --! If there are no line feeds we may have to break it down
                --! into smaller bit size chunks suitable for PRINT
                --!
                IF @InputLength > @MaxPrintLength
                    BEGIN
                        SET @WorkingString    = @InputString;
                        SET @WorkingLength    = LEN(@WorkingString);
                        SET @SubStringLength  = @MaxPrintLength;
                        WHILE @WorkingLength > 0
                            BEGIN
                                SET @SubString        = SUBSTRING(@WorkingString, 1, @SubStringLength);
                                SET @SubStringLength  = LEN(@SubString)
                                --!
                                --! If we still have text to process, set working values
                                --!
                                IF (@WorkingLength - @SubStringLength + 1) > 0
                                    BEGIN
                                        PRINT @SubString;
                                        --! Remove the text we've just processed
                                        SET @WorkingString    = SUBSTRING(@WorkingString, @SubStringLength + 1, @WorkingLength);
                                        SET @WorkingLength    = LEN(@WorkingString);
                                    END
                            END
                    END
                ELSE
                    PRINT @InputString;
            END --[BREAK_BY_LENGTH]
    --/////////////////////////////////////////////////////////////////////////////////////////////////
    OnComplete:
    --/////////////////////////////////////////////////////////////////////////////////////////////////
        SET NOCOUNT OFF
        RETURN
    END
    GO
    

    其次,我创建了一个临时表来存储所有相关实体,以便稍后可以使用它来打印我的脚本。临时表中包含一个“顺序”列,用于对删除语句进行降序排列,对创建语句进行升序排列。

    CREATE TABLE #DependentEntitiesInformation
    (
        ObjectId INT,
        SchemaName NVARCHAR(MAX),
        EntityName NVARCHAR(MAX),
        ObjectDefinition NVARCHAR(MAX),
        [Type] NVARCHAR(MAX),
        [Order] NVARCHAR(100)
    )
    GO
    

    第三,我使用递归 CTE 填充我的临时表。在此示例中,我的父视图称为“dbo.Project_Expanded”。

    SET NOCOUNT ON;
    
    DECLARE @ObjectSchemaAndEntity NVARCHAR(MAX) = 'dbo.Project_Expanded';
    
    WITH DependentEntities (ObjectId, SchemaName, EntityName, ObjectDefinition, [Type],[Order])
    AS
    (
        SELECT 
            e.referencing_id,
            e.referencing_schema_name, 
            e.referencing_entity_name,
            OBJECT_DEFINITION (e.referencing_id), 
            ao.[type],
            CAST(ROW_NUMBER() OVER(ORDER BY e.referencing_id) AS NVARCHAR(100))
        FROM 
            sys.dm_sql_referencing_entities (@ObjectSchemaAndEntity, 'OBJECT') e INNER JOIN
            sys.all_objects ao ON ao.[object_id] = e.referencing_id
        UNION ALL
        SELECT 
            e.referencing_id,
            e.referencing_schema_name, 
            e.referencing_entity_name,
            OBJECT_DEFINITION (e.referencing_id), 
            ao.[type],
            CAST(de.[Order] + '.' + CAST(ROW_NUMBER() OVER(ORDER BY e.referencing_id) AS NVARCHAR(100)) AS NVARCHAR(100))
        FROM 
            DependentEntities de OUTER APPLY
            sys.dm_sql_referencing_entities (de.SchemaName + '.' + de.EntityName, 'OBJECT') e INNER JOIN
            sys.all_objects ao ON ao.[object_id] = e.referencing_id 
    )
    INSERT INTO 
        #DependentEntitiesInformation
    SELECT 
        ObjectId,
        SchemaName, 
        EntityName,
        ObjectDefinition, 
        [Type],
        [Order]
    FROM 
        DependentEntities
    GO
    

    第四,我创建了 drop 语句,然后使用临时表创建了 create 语句,然后复制了结果。请注意,我的版本仅处理内联表值函数、过程和视图。如果您需要处理更多对象类型,则需要对其进行更新。

    DECLARE @StatementEnd NVARCHAR(4000) = CHAR(13) + CHAR(10) + 'GO' + CHAR(13) + CHAR(10) + CHAR(13) + CHAR(10);
    
    DECLARE @DropStatements NVARCHAR(MAX) = 
        (
            SELECT
                STRING_AGG(
                    'DROP ' + 
                    CASE
                        WHEN [Type] = 'IF' THEN 'FUNCTION'
                        WHEN [Type] = 'P' THEN 'PROCEDURE'
                        WHEN [Type] = 'V' THEN 'VIEW'
                    END + 
                    ' [' + SchemaName + '].[' + EntityName + ']', 
                    @StatementEnd
                ) WITHIN GROUP (ORDER BY [Order] DESC)
            FROM 
                #DependentEntitiesInformation
        ) + @StatementEnd;
    
    EXEC @DropStatements = [dbo].[PrintString] @DropStatements, 4000
    
    DECLARE @CreateStatements NVARCHAR(MAX) = 
        (
            SELECT 
                STRING_AGG(ObjectDefinition, @StatementEnd) WITHIN GROUP (ORDER BY [Order])
            FROM 
                #DependentEntitiesInformation
        );
    
    EXEC @CreateStatements = [dbo].[PrintString] @CreateStatements, 4000
    
    DECLARE @Statement NVARCHAR(MAX) = @DropStatements + @CreateStatements;
    
    EXEC [dbo].[PrintString] @Statement, 4000
    GO
    

    最后,我清理临时表并删除“PrintString”过程:

    DROP TABLE #DependentEntitiesInformation
    GO
    
    DROP PROCEDURE [dbo].[PrintString]
    GO
    
    • 1

相关问题

  • SQL Server - 使用聚集索引时如何存储数据页

  • 我需要为每种类型的查询使用单独的索引,还是一个多列索引可以工作?

  • 什么时候应该使用唯一约束而不是唯一索引?

  • 死锁的主要原因是什么,可以预防吗?

  • 如何确定是否需要或需要索引

Sidebar

Stats

  • 问题 205573
  • 回答 270741
  • 最佳答案 135370
  • 用户 68524
  • 热门
  • 回答
  • Marko Smith

    连接到 PostgreSQL 服务器:致命:主机没有 pg_hba.conf 条目

    • 12 个回答
  • Marko Smith

    如何让sqlplus的输出出现在一行中?

    • 3 个回答
  • Marko Smith

    选择具有最大日期或最晚日期的日期

    • 3 个回答
  • Marko Smith

    如何列出 PostgreSQL 中的所有模式?

    • 4 个回答
  • Marko Smith

    列出指定表的所有列

    • 5 个回答
  • Marko Smith

    如何在不修改我自己的 tnsnames.ora 的情况下使用 sqlplus 连接到位于另一台主机上的 Oracle 数据库

    • 4 个回答
  • Marko Smith

    你如何mysqldump特定的表?

    • 4 个回答
  • Marko Smith

    使用 psql 列出数据库权限

    • 10 个回答
  • Marko Smith

    如何从 PostgreSQL 中的选择查询中将值插入表中?

    • 4 个回答
  • Marko Smith

    如何使用 psql 列出所有数据库和表?

    • 7 个回答
  • Martin Hope
    Jin 连接到 PostgreSQL 服务器:致命:主机没有 pg_hba.conf 条目 2014-12-02 02:54:58 +0800 CST
  • Martin Hope
    Stéphane 如何列出 PostgreSQL 中的所有模式? 2013-04-16 11:19:16 +0800 CST
  • Martin Hope
    Mike Walsh 为什么事务日志不断增长或空间不足? 2012-12-05 18:11:22 +0800 CST
  • Martin Hope
    Stephane Rolland 列出指定表的所有列 2012-08-14 04:44:44 +0800 CST
  • Martin Hope
    haxney MySQL 能否合理地对数十亿行执行查询? 2012-07-03 11:36:13 +0800 CST
  • Martin Hope
    qazwsx 如何监控大型 .sql 文件的导入进度? 2012-05-03 08:54:41 +0800 CST
  • Martin Hope
    markdorison 你如何mysqldump特定的表? 2011-12-17 12:39:37 +0800 CST
  • Martin Hope
    Jonas 如何使用 psql 对 SQL 查询进行计时? 2011-06-04 02:22:54 +0800 CST
  • Martin Hope
    Jonas 如何从 PostgreSQL 中的选择查询中将值插入表中? 2011-05-28 00:33:05 +0800 CST
  • Martin Hope
    Jonas 如何使用 psql 列出所有数据库和表? 2011-02-18 00:45:49 +0800 CST

热门标签

sql-server mysql postgresql sql-server-2014 sql-server-2016 oracle sql-server-2008 database-design query-performance sql-server-2017

Explore

  • 主页
  • 问题
    • 最新
    • 热门
  • 标签
  • 帮助

Footer

AskOverflow.Dev

关于我们

  • 关于我们
  • 联系我们

Legal Stuff

  • Privacy Policy

Language

  • Pt
  • Server
  • Unix

© 2023 AskOverflow.DEV All Rights Reserve