AskOverflow.Dev

AskOverflow.Dev Logo AskOverflow.Dev Logo

AskOverflow.Dev Navigation

  • Início
  • system&network
  • Ubuntu
  • Unix
  • DBA
  • Computer
  • Coding
  • LangChain

Mobile menu

Close
  • Início
  • system&network
    • Recentes
    • Highest score
    • tags
  • Ubuntu
    • Recentes
    • Highest score
    • tags
  • Unix
    • Recentes
    • tags
  • DBA
    • Recentes
    • tags
  • Computer
    • Recentes
    • tags
  • Coding
    • Recentes
    • tags
Início / dba / Perguntas / 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

Scripting drop/create de dependências ao alterar a visualização com schemabinding

  • 772

No SQL Server 2017, tenho uma exibição, "ParentView", que é referenciada por outras exibições "ChildView1", "ChildView2", etc. Essas exibições são referenciadas por outras exibições "GrandChildView1", "GrandChildView2", etc. e assim por diante e assim por diante adiante. Certifico-me de configurar todas as minhas visualizações para ter "COM SCHEMABINDING". Quando quero fazer uma alteração em "ParentView", sou obrigado a descartar e criar todas as visualizações dependentes. Isso, é claro, faz todo o sentido porque eu tenho "COM SCHEMABINDING" ativado e poderia estar fazendo uma alteração que poderia quebrar uma das visualizações dependentes. No entanto, fazer tudo isso é tedioso através da interface do usuário, então eu queria saber ...

Como posso obter um script que recebe uma exibição ou qualquer objeto como entrada e cria uma instrução drop/create com base em dependências?

Por exemplo:

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

Notas

  • Isso não precisa ser específico para visualizações. Eu também tenho funções dependentes e procedimentos armazenados também.
  • Nenhuma das minhas visualizações são visualizações indexadas.
sql-server sql-server-2017
  • 1 1 respostas
  • 619 Views

1 respostas

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

    Eu encontrei uma maneira de fazer isso usando alguns scripts diferentes.

    Primeiro, eu precisava configurar o procedimento armazenado "PrintString" de Greg M. Lucas para imprimir todas as minhas instruções sem que elas fossem truncadas.

    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
    

    Segundo, criei uma tabela temporária para armazenar todas as entidades dependentes para que eu possa usá-la posteriormente para imprimir meu script. Incluída na tabela temporária está uma coluna "Order" para fazer a ordem decrescente nas instruções drop e a ordem crescente nas instruções create.

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

    Terceiro, preencho minha tabela temporária usando um CTE recursivo. Neste exemplo, minha visualização pai é chamada de '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
    

    Quarto, eu crio minhas instruções drop e, em seguida, minhas instruções create usando minha tabela temporária e copio os resultados. Observe que minha versão lida apenas com funções, procedimentos e exibições com valor de tabela embutidos. Você precisará atualizá-lo se precisar manipular mais tipos de objeto.

    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
    

    Por fim, limpo a tabela temporária e descarto o procedimento "PrintString":

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

relate perguntas

  • SQL Server - Como as páginas de dados são armazenadas ao usar um índice clusterizado

  • Preciso de índices separados para cada tipo de consulta ou um índice de várias colunas funcionará?

  • Quando devo usar uma restrição exclusiva em vez de um índice exclusivo?

  • Quais são as principais causas de deadlocks e podem ser evitadas?

  • Como determinar se um Índice é necessário ou necessário

Sidebar

Stats

  • Perguntas 205573
  • respostas 270741
  • best respostas 135370
  • utilizador 68524
  • Highest score
  • respostas
  • Marko Smith

    conectar ao servidor PostgreSQL: FATAL: nenhuma entrada pg_hba.conf para o host

    • 12 respostas
  • Marko Smith

    Como fazer a saída do sqlplus aparecer em uma linha?

    • 3 respostas
  • Marko Smith

    Selecione qual tem data máxima ou data mais recente

    • 3 respostas
  • Marko Smith

    Como faço para listar todos os esquemas no PostgreSQL?

    • 4 respostas
  • Marko Smith

    Listar todas as colunas de uma tabela especificada

    • 5 respostas
  • Marko Smith

    Como usar o sqlplus para se conectar a um banco de dados Oracle localizado em outro host sem modificar meu próprio tnsnames.ora

    • 4 respostas
  • Marko Smith

    Como você mysqldump tabela (s) específica (s)?

    • 4 respostas
  • Marko Smith

    Listar os privilégios do banco de dados usando o psql

    • 10 respostas
  • Marko Smith

    Como inserir valores em uma tabela de uma consulta de seleção no PostgreSQL?

    • 4 respostas
  • Marko Smith

    Como faço para listar todos os bancos de dados e tabelas usando o psql?

    • 7 respostas
  • Martin Hope
    Jin conectar ao servidor PostgreSQL: FATAL: nenhuma entrada pg_hba.conf para o host 2014-12-02 02:54:58 +0800 CST
  • Martin Hope
    Stéphane Como faço para listar todos os esquemas no PostgreSQL? 2013-04-16 11:19:16 +0800 CST
  • Martin Hope
    Mike Walsh Por que o log de transações continua crescendo ou fica sem espaço? 2012-12-05 18:11:22 +0800 CST
  • Martin Hope
    Stephane Rolland Listar todas as colunas de uma tabela especificada 2012-08-14 04:44:44 +0800 CST
  • Martin Hope
    haxney O MySQL pode realizar consultas razoavelmente em bilhões de linhas? 2012-07-03 11:36:13 +0800 CST
  • Martin Hope
    qazwsx Como posso monitorar o andamento de uma importação de um arquivo .sql grande? 2012-05-03 08:54:41 +0800 CST
  • Martin Hope
    markdorison Como você mysqldump tabela (s) específica (s)? 2011-12-17 12:39:37 +0800 CST
  • Martin Hope
    Jonas Como posso cronometrar consultas SQL usando psql? 2011-06-04 02:22:54 +0800 CST
  • Martin Hope
    Jonas Como inserir valores em uma tabela de uma consulta de seleção no PostgreSQL? 2011-05-28 00:33:05 +0800 CST
  • Martin Hope
    Jonas Como faço para listar todos os bancos de dados e tabelas usando o psql? 2011-02-18 00:45:49 +0800 CST

Hot tag

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

Explore

  • Início
  • Perguntas
    • Recentes
    • Highest score
  • tag
  • help

Footer

AskOverflow.Dev

About Us

  • About Us
  • Contact Us

Legal Stuff

  • Privacy Policy

Language

  • Pt
  • Server
  • Unix

© 2023 AskOverflow.DEV All Rights Reserve