Sql 添加之前,请检查扩展属性描述是否已存在

Sql 添加之前,请检查扩展属性描述是否已存在,sql,sql-server,exists,extended-properties,database-table,Sql,Sql Server,Exists,Extended Properties,Database Table,因此,我有一个添加扩展属性的脚本,一些描述表,一些描述列。如何在添加扩展属性之前检查它是否存在,以便脚本不会引发错误?第一个脚本检查描述表的扩展属性是否存在: 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_addextend

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

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

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';

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

IF EXISTS(SELECT 1 FROM sys.extended_properties WHERE [major_id] = OBJECT_ID('<schema>.<table_name>') AND [name] = N'MS_Description')
查询sys.extended_properties目录视图以获取数据库中的所有扩展属性


有关更多详细信息,请使用

我编写了一个简单的存储过程来添加或更新扩展属性“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

下面是另一种存储过程方法,类似于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

也许我的回答没有直接联系到这个问题,但我想指出的是,MS_描述实际上是区分大小写的,即使我们用SQL添加它。如果我们使用MS_描述而不是MS_描述,它将不会显示在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'

GO

请查找我对上面Brian Westrich答案的扩展,但此版本允许更新和添加表和列上的任何扩展属性,而不仅仅是MS_描述。此外,它还允许您使用存储过程在不同的数据库中添加和更新扩展属性,以便在服务器上只需要一个副本

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

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

要按架构枚举MS_描述属性,请使用-

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_描述属性之前检查该属性是否不存在,请在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函数,但这应该可以满足您的要求。

我喜欢这种方法,但是我遇到了一个实例,在执行此查询后,我有一个打开的事务。``Msg 266,16级,状态2,Procedure up_DATADECT,第178行EXECUTE后的事务计数表示BEGIN和COMMIT语句的数量不匹配。上一次计数=0,当前计数=1```我在下面发布了一个类似的方法,它不使用try/catch,事务回滚也不那么优雅,但避免了DamianUsage提出的问题。但是,使用异常处理来控制程序流,即使用IF语句可以做什么,这是一个错误!。看这个。。。一般来说,至少在历史上,只要问题/答案提供价值,那么SO允许这样做。我相信,他们确实要求你在接受自己的答案之前提供一些时间,让其他人也回答,并且客观地选择最佳答案,而不仅仅是将自己的答案标记为正确以获得+代表。因此这很好,唯一令人担心的是,人们在接受自己的答案之前,没有给其他人时间提供答案。重要提示:如果在同一数据库中有两个名称相同但模式不同的表,则If条件将失败。如果我不是SQL Server硬用户,我将尝试找到一种方法来指定该条件的模式,我将在这里分享我的发现。
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