【问题标题】:Get missing columns from a list of expected columns in a table从表中的预期列列表中获取缺失的列
【发布时间】:2020-10-14 03:45:51
【问题描述】:

测试有一个预期列的列表,用于验证实际表是否有它们。断言是如果计数在预期和实际中相等,则所有列都存在。

如何提取缺少的列以放入更有意义的错误消息中?

感谢您的帮助。

-- Verify added columns exist
CREATE PROC [testComplianceMaintenanceReporting].[test FactPropertyLatestRepairJobAgg_ColumnsExist]
AS
BEGIN
    SET NOCOUNT ON

    -- Assemble
    IF OBJECT_ID('tempdb..#TempExpected') IS NOT NULL
    BEGIN
        DROP TABLE #TempExpected
    END
    CREATE TABLE #TempExpected
    (
        Id INT,
        ColumnName NVARCHAR(50)
    )
    INSERT INTO #TempExpected
        VALUES
            (1, 'TenancyKey'),
            (2, 'TenancyHouseholdTypeKey'),
            (3, 'HomeVisitKeyLatest'),
            (4, 'HomeVisitDueStatusKey'),
            (5, 'HousingApplicationKey'),
            (6, 'RepairAreaKeyPropertyDefault'),
            (7, 'ContractKeyPropertyDefaultPMSCService'),
            (8, 'ContractorKeyPropertyDefaultHeadContractor'),
            (9, 'NextPeriodicHomeVisitDate'),
            (10, 'CountOfActiveLeaseAgreements')

    -- Action
    IF OBJECT_ID('tempdb..#TempActual') IS NOT NULL
    BEGIN
        DROP TABLE #TempActual
    END
    SELECT * INTO #TempActual
    FROM
    (
        SELECT
            OBJECT_ID,
            NAME
        FROM SYS.COLUMNS
        WHERE
            OBJECT_ID = OBJECT_ID('dm.Fact_PropertyLatestRepairJobAgg')
            AND NAME IN (SELECT ColumnName FROM #TempExpected)
    ) [TempActual]

    -- Assert
    DECLARE @expectedCount INT = (
        SELECT COUNT(*) FROM #TempExpected
    )
    DECLARE @actualCount INT = (
        SELECT COUNT(*) FROM #TempActual
    )
    EXEC tSQLt.AssertEquals
    @Expected = @expectedCount,
    @Actual = @actualCount,
    @Message = 'There are missing columns'
END
GO

【问题讨论】:

    标签: sql sql-server tsql sql-server-2016 tsqlt


    【解决方案1】:

    在您断言 @actualCount 的测试条件的地方,我相信您的意思是 INNER JOIN 到 #TempExpected 表。这将确认实际值是正确的值。否则,实际行可能不包含预期的 ColumnName。要创建缺失列名的列表,查询使用 STRING_AGG 和 NOT EXISTS。像这样的

        -- Assert
        DECLARE @expectedCount INT = (
            SELECT COUNT(*) FROM #TempExpected
        );
        DECLARE @actualCount INT = (
            SELECT COUNT(*) 
            FROM #TempActual ta
                 join #expectedCount ec on ta.ColumnName=ec.ColumnName 
        );
        DECLARE @missing_ColumnName_message varchar(200);
        select @missing_ColumnName_message = (
            select concat('There are missing columns: ', string_agg(ec.ColumnName, ','))
            from #expectedCount ec
            where not exists(select 1
                             from #TempActual ta
                             where ta.ColumnName=ec.ColumnName)
        );
        EXEC tSQLt.AssertEquals
        @Expected = @expectedCount,
        @Actual = @actualCount,
        @Message = @missing_ColumnName_message;
    

    不带STRING_AGG 的旧版本SQL Server 可以使用STUFFFOR XML

    -- Assert
        DECLARE @expectedCount INT = (
            SELECT COUNT(*) FROM #TempExpected
        );
        DECLARE @actualCount INT = (
            SELECT COUNT(*) 
            FROM #TempActual ta
                 join #expectedCount ec on ta.ColumnName=ec.ColumnName 
        );
        DECLARE @missing_ColumnName_message varchar(200);
        select @missing_ColumnName_message = (
            select concat('There are missing columns: ',
                          (stuff((select ', ' + ec.ColumnName
                           from #expectedCount ec
                           where not exists(select 1
                                            from #TempActual ta
                                            where ta.ColumnName=ec.ColumnName)
                           order by 1
                           for xml path('')),1,1,'')))
        );
        EXEC tSQLt.AssertEquals
        @Expected = @expectedCount,
        @Actual = @actualCount,
        @Message = @missing_ColumnName_message;
    

    【讨论】:

    • 嗨@SteveC,忘了提到我们在 SQL Server 2016 中,string_agg 正在返回错误:'string_agg' is not a recognized built-in function name
    【解决方案2】:

    tSQLt 已经为此内置了一个断言,它可以验证列名、位置、数据类型和可空性。另外,在我看来,一个更优雅的解决方案:

    create procedure [UserProfileTests].[test Attribute column structure]
    as
    begin
        create table [UserProfileTests].[expected]
        (
          AttributeId int not null
        , AttributeName varchar(50) not null
        , DotNetType varchar(100) null
        , Narrative varchar(500) null,
        );
    
        exec tSQLt.AssertEqualsTableSchema '[UserProfileTests].[expected]', 'UserProfile.Attribute';
    end;
    go
    

    ...您得到的结果将使您能够快速识别丢失/无效的内容

    【讨论】:

    • 嗨@datacentricity,很高兴知道这个断言。它是否断言整个表?对于添加的上下文,预期的 10 列是现有表中新添加列的部分列表,因此仅检查添加的列。
    • 是的,它会验证整个表,因此如果您遵循真正的 TDD,您将在测试中将新列添加到表定义中,运行测试,它会失败,然后将列添加到表以便测试通过。
    【解决方案3】:

    感谢@SteveC,我最终得到了这样的结果:

        -- Assert
        DECLARE @expectedCount INT = (
            SELECT COUNT(*) FROM #TempExpected
        )
        DECLARE @actualCount INT = (
            SELECT COUNT(*) 
            FROM #TempActual [TA]
            JOIN #TempExpected [TE] ON TA.Name = TE.ColumnName 
        )
        DECLARE @missingColumns NVARCHAR(MAX)
        SELECT @missingColumns = COALESCE(@missingColumns + ', ' + MissingColumn, MissingColumn) 
            FROM
            (
                SELECT TE.ColumnName [MissingColumn]
                FROM #TempExpected [TE]
                WHERE NOT EXISTS
                (
                    SELECT 1
                    FROM #TempActual [TA]
                    WHERE TA.Name = TE.ColumnName
                )           
            ) [MissingColumns]
        DECLARE @errMsg NVARCHAR(MAX) = (
            SELECT CONCAT('Missing columns: ', @missingColumns)
        )
        EXEC tSQLt.AssertEquals
            @Expected = @expectedCount,
            @Actual = @actualCount,
            @Message = @errMsg
    

    输出:

    参考使用COALESCE:

    https://www.mytecbits.com/microsoft/sql-server/concatenate-multiple-rows-into-single-string

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2013-09-15
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-08-06
      • 1970-01-01
      相关资源
      最近更新 更多