从 table 中的预期列列表中获取缺失的列
Get missing columns from a list of expected columns in a table
测试有一个预期列的列表,用于验证实际 table 是否有它们。断言是如果预期计数和实际计数相等,则所有列都存在。
如何提取缺少的列以放入更有意义的错误消息中?
感谢您的帮助。
-- 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
你断言@actualCount 的测试条件的地方我相信你的意思是 INNER JOIN 到 #TempExpected table。这将确认实际值是正确的值。否则,实际行可能不包含预期的 ColumnNames。要创建缺少列名的列表,查询使用 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;
旧版本的 SQL Server
没有 STRING_AGG
可以使用 STUFF
和 FOR 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,这就是我最终得到的结果:
-- 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
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
...您得到的结果将使您能够快速识别什么是 missing/invalid
测试有一个预期列的列表,用于验证实际 table 是否有它们。断言是如果预期计数和实际计数相等,则所有列都存在。
如何提取缺少的列以放入更有意义的错误消息中?
感谢您的帮助。
-- 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
你断言@actualCount 的测试条件的地方我相信你的意思是 INNER JOIN 到 #TempExpected table。这将确认实际值是正确的值。否则,实际行可能不包含预期的 ColumnNames。要创建缺少列名的列表,查询使用 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;
旧版本的 SQL Server
没有 STRING_AGG
可以使用 STUFF
和 FOR 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,这就是我最终得到的结果:
-- 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
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
...您得到的结果将使您能够快速识别什么是 missing/invalid