【问题标题】:Check if extended property description already exists before adding在添加之前检查扩展属性描述是否已经存在
【发布时间】:2013-06-14 22:13:54
【问题描述】:

所以,我有一个添加扩展属性的脚本,一些描述一个表,一些描述一个列。如何在添加之前检查扩展属性是否存在,以便脚本不会抛出错误?

【问题讨论】:

    标签: sql sql-server exists extended-properties database-table


    【解决方案1】:

    第一个脚本检查描述表的扩展属性是否存在:

    IF NOT EXISTS (SELECT NULL FROM SYS.EXTENDED_PROPERTIES WHERE [major_id] = OBJECT_ID('Table_Name') AND [name] = N'MS_Description' AND [minor_id] = 0)
    EXECUTE sp_addextendedproperty @name = N'MS_Description', @value = N'This table is responsible for holding information.', @level0type = N'SCHEMA', @level0name = N'dbo', @level1type = N'TABLE', @level1name = N'Table_Name';
    

    第二个脚本检查描述列的扩展属性是否存在:

    IF NOT EXISTS (SELECT NULL FROM SYS.EXTENDED_PROPERTIES WHERE [major_id] = OBJECT_ID('Table_Name') AND [name] = N'MS_Description' AND [minor_id] = (SELECT [column_id] FROM SYS.COLUMNS WHERE [name] = 'Column_Name' AND [object_id] = OBJECT_ID('Table_Name')))
    EXECUTE sp_addextendedproperty @name = N'MS_Description', @value = N'This column is responsible for holding information for table Table_Name.', @level0type = N'SCHEMA', @level0name = N'dbo', @level1type = N'TABLE', @level1name = N'Table_Name', @level2type = N'COLUMN', @level2name = N'Column_Name';
    

    【讨论】:

    • 一般来说,至少从历史上看,只要问题/答案提供价值,SO 就允许这样做。我相信他们确实会要求您在接受自己的答案之前提供一些时间以允许其他人也回答,并且您客观地选择最佳答案,而不仅仅是将您自己的答案标记为正确以获得 +rep。所以这很好,唯一担心的是人们在接受自己的答案之前没有给其他人时间提供答案。
    • 重要:如果您在同一个数据库中有两个同名但在不同架构中的表,则if 条件将失败。我正在尝试找到一种方法来为 IF 条件指定架构(我不是 SQL Server 硬用户),我会在这里分享我找到的。
    【解决方案2】:

    这是另一种存储过程方法,类似于 Ruslan K. 的方法,但不涉及 try/catch 或显式事务:

    -- simplify syntax for maintaining data dictionary
    
    IF OBJECT_ID ('dbo.usp_addorupdatedescription', 'P') IS NOT NULL
        DROP PROCEDURE dbo.usp_addorupdatedescription;
    GO
    
    CREATE PROCEDURE usp_addorupdatedescription
            @table nvarchar(128),  -- table name
            @column nvarchar(128), -- column name, NULL if description for table
            @descr sql_variant     -- description text
    AS
        BEGIN
            SET NOCOUNT ON;
    
            IF @column IS NOT NULL
                IF NOT EXISTS (SELECT NULL FROM SYS.EXTENDED_PROPERTIES
                WHERE [major_id] = OBJECT_ID(@table) AND [name] = N'MS_Description'
                      AND [minor_id] = (SELECT [column_id]
                                        FROM SYS.COLUMNS WHERE [name] = @column AND [object_id] = OBJECT_ID(@table)))
                    EXECUTE sp_addextendedproperty @name = N'MS_Description', @value = @descr,
                                                   @level0type = N'SCHEMA', @level0name = N'dbo', @level1type = N'TABLE',
                                                   @level1name = @table, @level2type = N'COLUMN', @level2name = @column;
                ELSE
                    EXECUTE sp_updateextendedproperty @name = N'MS_Description',
                                                      @value = @descr, @level0type = N'SCHEMA', @level0name = N'dbo',
                                                      @level1type = N'TABLE', @level1name = @table,
                                                      @level2type = N'COLUMN', @level2name = @column;
            ELSE
                IF NOT EXISTS (SELECT NULL FROM SYS.EXTENDED_PROPERTIES
                WHERE [major_id] = OBJECT_ID(@table) AND [name] = N'MS_Description'
                      AND [minor_id] = 0)
                    EXECUTE sp_addextendedproperty @name = N'MS_Description', @value = @descr,
                                                   @level0type = N'SCHEMA', @level0name = N'dbo',
                                                   @level1type = N'TABLE', @level1name = @table;
                ELSE
                    EXECUTE sp_updateextendedproperty @name = N'MS_Description', @value = @descr,
                                                      @level0type = N'SCHEMA', @level0name = N'dbo',
                                                      @level1type = N'TABLE', @level1name = @table;
        END
    GO
    

    【讨论】:

      【解决方案3】:

      我编写了简单的存储过程来添加或更新扩展属性“MS_Description”:

      IF OBJECT_ID ('dbo.usp_addorupdatedescription', 'P') IS NOT NULL
          DROP PROCEDURE dbo.usp_addorupdatedescription;
      GO
      
      CREATE PROCEDURE usp_addorupdatedescription
          @table nvarchar(128),  -- table name
          @column nvarchar(128), -- column name, NULL if description for table
          @descr sql_variant     -- description text
      AS
      BEGIN
          SET NOCOUNT ON;
      
          DECLARE @c nvarchar(128) = NULL;
      
          IF @column IS NOT NULL
              SET @c = N'COLUMN';
      
          BEGIN TRY
              EXECUTE sp_updateextendedproperty  N'MS_Description', @descr, N'SCHEMA', N'dbo', N'TABLE', @table, @c, @column;
          END TRY
          BEGIN CATCH
              EXECUTE sp_addextendedproperty N'MS_Description', @descr, N'SCHEMA', N'dbo', N'TABLE', @table, @c, @column;
          END CATCH;
      END
      GO
      

      【讨论】:

      • 我喜欢这种方法,但是我遇到了一个实例,在执行此查询后我有打开事务。 ``` 消息 266,级别 16,状态 2,过程 up_DataDict,第 178 行 EXECUTE 后的事务计数指示 BEGIN 和 COMMIT 语句的数量不匹配。先前计数 = 0,当前计数 = 1。```
      • 我在下面发布了一个类似的方法,它不使用 try/catch,事务回滚(没有那么优雅,但避免了 Damian 提出的问题
      • 有用。然而,使用异常处理来控制程序流(即可以用 IF 语句做什么)是code smell!。看到这个stackoverflow question
      • .. 和this
      【解决方案4】:

      也许我的回答并没有直接连接到这个问题,但我想指出 MS_Description 实际上是区分大小写的,即使我们用 SQL 添加它。如果我们使用 MS_DESCRIPTION 而不是 MS_Description,它将不会显示在 SMSS 表设计视图中。

      在我的情况下,我必须做这样的事情来删除现有的描述并添加一个正确的描述。

      IF EXISTS (
          SELECT NULL
          FROM SYS.EXTENDED_PROPERTIES
          WHERE [major_id] = OBJECT_ID('TableName')
              AND [name] = N'MS_DESCRIPTION'
              AND [minor_id] = (
                  SELECT [column_id]
                  FROM SYS.COLUMNS
                  WHERE [name] = 'ColumnName'
                      AND [object_id] = OBJECT_ID('Tablename')
                  )
          )
          EXEC sys.sp_dropextendedproperty @name = N'MS_DESCRIPTION'
              ,@level0type = N'SCHEMA'
              ,@level0name = N'dbo'
              ,@level1type = N'TABLE'
              ,@level1name = N'TableName'
              ,@level2type = N'COLUMN'
              ,@level2name = N'ColumnName'
          GO
      
      EXEC sys.sp_addextendedproperty @name = N'MS_Description'
      ,@value = N'Description detail'
      ,@level0type = N'SCHEMA'
      ,@level0name = N'dbo'
      ,@level1type = N'TABLE'
      ,@level1name = N'TableName'
      ,@level2type = N'COLUMN'
      ,@level2name = N'ColumnName'
      

      【讨论】:

        【解决方案5】:

        请在上面找到我对 Brian Westrich 答案的扩展,但此版本允许更新和添加表和列上的任何扩展属性,而不仅仅是 MS_Description。此外,它还允许您使用存储过程来添加和更新不同数据库中的扩展属性,因此您只需要在服务器上复制一份。

        CREATE PROCEDURE dbo.AddOrUpdateExtendedProperty
             @Database      NVARCHAR(128)   -- Database name
            ,@Schema        NVARCHAR(128)   -- Schema name
            ,@Table         NVARCHAR(128)   -- Table name
            ,@Column        NVARCHAR(128)   -- Column name, NULL if description for table
            ,@PropertyName  NVARCHAR(128)   -- Property name
            ,@PropertyValue SQL_VARIANT     -- Property value
        AS
        BEGIN
            SET NOCOUNT ON;
        
            DECLARE @NSQL NVARCHAR(MAX);
        
            DECLARE @Level2Type NVARCHAR(128) = NULL;
        
            DECLARE @Params NVARCHAR(MAX) = N'@Schema NVARCHAR(128), @Table NVARCHAR(128), @Column NVARCHAR(128), @PropertyName NVARCHAR(128), @PropertyValue SQL_VARIANT';
        
            IF @Column IS NOT NULL
            BEGIN
                SET @NSQL = 'USE ' + @Database + ';
        
                    IF NOT EXISTS
                    (
                        SELECT NULL FROM sys.extended_properties
                         WHERE     major_id = OBJECT_ID(''' + @Schema + '.' + @Table + ''')
                               AND name = @PropertyName
                              AND minor_id = (SELECT column_id
                                                FROM sys.columns
                                               WHERE     name = @Column
                                                     AND object_id = OBJECT_ID(''' + @Schema + '.' + @Table + ''')
                                             )
                    )
                    BEGIN
                        EXECUTE sp_addextendedproperty
                             @name = @PropertyName
                            ,@value = @PropertyValue
                            ,@level0type = N''SCHEMA''
                            ,@level0name = @Schema
                            ,@level1type = N''TABLE''
                            ,@level1name = @Table
                            ,@level2type = N''COLUMN''
                            ,@level2name = @Column;
                    END
                    ELSE
                    BEGIN
                        EXECUTE sp_updateextendedproperty
                             @name = @PropertyName
                            ,@value = @PropertyValue
                            ,@level0type = N''SCHEMA''
                            ,@level0name = @Schema
                            ,@level1type = N''TABLE''
                            ,@level1name = @Table
                            ,@level2type = N''COLUMN''
                            ,@level2name = @Column;
                    END
                ';
        
                EXECUTE sp_executesql
                     @NSQL
                    ,@Params
                    ,@Schema
                    ,@Table
                    ,@Column
                    ,@PropertyName
                    ,@PropertyValue;
            END
            ELSE
            BEGIN
                SET @NSQL = 'USE ' + @Database + ';
        
                    IF NOT EXISTS
                    (
                        SELECT NULL
                          FROM sys.extended_properties
                         WHERE     major_id = OBJECT_ID(''' + @Schema + '.' + @Table + ''')
                               AND name = @PropertyName
                               AND minor_id = 0
                    )
                    BEGIN
                        EXECUTE sp_addextendedproperty
                             @name = @PropertyName
                            ,@value = @PropertyValue
                            ,@level0type = N''SCHEMA''
                            ,@level0name = @Schema
                            ,@level1type = N''TABLE''
                            ,@level1name = @Table;
                    END
                    ELSE
                    BEGIN
                        EXECUTE sp_updateextendedproperty
                             @name = @PropertyName
                            ,@value = @PropertyValue
                            ,@level0type = N''SCHEMA''
                            ,@level0name = @Schema
                            ,@level1type = N''TABLE''
                            ,@level1name = @Table;
                    END
                ';
        
                EXECUTE sp_executesql
                     @NSQL
                    ,@Params
                    ,@Schema
                    ,@Table
                    ,@Column
                    ,@PropertyName
                    ,@PropertyValue;
            END
        END
        

        【讨论】:

          【解决方案6】:

          检查任何可用于给定表的扩展属性,如下所示。

          IF EXISTS(SELECT 1 FROM sys.extended_properties WHERE [major_id] = OBJECT_ID('<schema>.<table_name>') AND [name] = N'MS_Description')
          

          如果您的表有多个扩展属性,请将列 ID 指定为 minor_id

          IF EXISTS(SELECT 1 FROM sys.extended_properties WHERE [major_id] = OBJECT_ID('<schema>.<table_name>') AND [name] = N'MS_Description' AND minor_id = 3)
          

          查询sys.extended_properties 目录视图以获取数据库中的所有扩展属性。

          更多详情请使用http://msdn.microsoft.com/en-us/library/ms177541(v=sql.110).aspx

          【讨论】:

            【解决方案7】:

            基于 ScubaSteve 的回答,以下查询将允许您按名称检查指定架构内的列或表上的 MS_Description 属性。要检查表,只需将谓词 c.name = '&lt;column&gt;' 替换为 c.name IS NULLd.minor_id = 0

            按架构使用枚举 MS_Description 属性 -

            SELECT a.name as [schema], b.name as [table], c.name as [column], d.name, d.value
            FROM sys.schemas a
            JOIN sys.tables b ON a.schema_id = b.schema_id
            LEFT JOIN sys.columns c ON b.object_id = c.object_id
            JOIN sys.extended_properties d ON d.major_id = b.object_id AND d.minor_id = ISNULL(c.column_id,0)
            WHERE a.name = '<schema>' AND b.name = '<table>' AND c.name = '<column>' AND d.name = 'MS_Description'
            

            在添加之前检查 MS_Description 属性是否不存在,用 - 将您的 add 语句括起来

            IF NOT EXISTS (SELECT 1 FROM sys.schemas a JOIN sys.tables b ON a.schema_id = b.schema_id LEFT JOIN sys.columns c ON b.object_id = c.object_id JOIN sys.extended_properties d ON d.major_id = b.object_id AND d.minor_id = ISNULL(c.column_id,0)
                           WHERE a.name = '<schema>' AND b.name = '<table>' AND c.name = '<column>' AND d.name = 'MS_Description'
                           )
            BEGIN
                --EXEC sp_addextendedproperty statement goes here
            END
            

            这些查询中的连接可能会更好地排序以消除 ISNULL 函数,但这应该会得到您想要的。

            【讨论】:

              猜你喜欢
              • 2010-12-21
              • 1970-01-01
              • 2011-11-16
              • 1970-01-01
              • 1970-01-01
              • 2014-01-14
              • 1970-01-01
              • 1970-01-01
              • 2022-01-24
              相关资源
              最近更新 更多