我正在尝试编写一个存储过程,在我们的客户尝试升级之前检查孤立数据,因为孤立记录可能会导致问题。这是我到目前为止所拥有的;
IF EXISTS (SELECT * FROM sys.objects WHERE type = 'P' AND name = 'DetectOrphanDataBeforeUpgrade')
DROP PROCEDURE [dbo].[DetectOrphanDataBeforeUpgrade]
GO
CREATE PROCEDURE [dbo].[DetectOrphanDataBeforeUpgrade]
@TenantId INT = NULL
AS
BEGIN
DECLARE @OrphanAuditItems NVARCHAR(MAX)
DECLARE @OrphanAuditAnswers NVARCHAR(MAX)
DECLARE @OrphanAuditQuestion NVARCHAR(MAX)
------------------------------------------------------------------------------------------------
/* Throw an error if the TenantId is NULL or Invalid. */
------------------------------------------------------------------------------------------------
IF @TenantId IS NULL OR @TenantId NOT IN (SELECT Tenants FROM [Application].[dbo].[TenantIdNumber])
BEGIN
THROW 51000, '@TenantId is invalid because it is NULL or does not exist.', 1;
END
------------------------------------------------------------------------------------------------
/* Checks for Orphan records related to the Audits table */
------------------------------------------------------------------------------------------------
SET @OrphanAuditItems = N'SELECT COUNT(*) FROM [Dynamic].['+ CAST (@TenantId AS NVARCHAR) +'].[AuditItems]
WHERE FK_Audit NOT IN (SELECT SystemID FROM [Dynamic].['+ CAST (@TenantId AS NVARCHAR) +'].[Audits])'
SET @OrphanAuditAnswers = N'SELECT COUNT(*) FROM [Dynamic].['+ CAST (@TenantId AS NVARCHAR) +'].[AuditAnswers]
WHERE AuditItemId NOT IN (SELECT SystemID FROM [Dynamic].['+ CAST (@TenantId AS NVARCHAR) +'].[AuditItems])'
SET @OrphanAuditQuestion = N'SELECT COUNT(*) FROM [Dynamic].['+ CAST (@TenantId AS NVARCHAR) +'].[AuditQuestion]
WHERE AuditId NOT IN (SELECT SystemID FROM [Dynamic].['+ CAST (@TenantId AS NVARCHAR) +'].[Audits])'
EXEC (@OrphanAuditItems)
EXEC(@OrphanAuditAnswers)
EXEC(@OrphanAuditQuestion)
END;
目前,这个脚本正在运行,但是输出是;
我想在一行中返回结果,并让每一列都有自己的名称,例如:@OrphanAuditItems 结果显示为列名:OrphanAuditItems,等等。
实现这一目标的最佳方法是什么?
谢谢,汤姆
您需要将 3 个动态 SQL 混合为 1 个返回 3 列,或者保留每个动态 SQL 但在最后混合它们的结果。有以下 2 种可能的解决方案:
一种解决方案是使用
UNION ALL
和PIVOT
来获取 1 行 3 列,所有这些都在动态 SQL 中。更改此部分:
为了这:
确保
PRINT
在执行之前使用 来验证生成的 SQLEXEC
。sp_executesql
另一种解决方案是使用withOUTPUT
参数将值检索到变量中:我发现后者比第一个更灵活和可读。
一种方法是对每一列使用子查询。下面的示例也使用
QUOTENAME
来包含标识符。就个人而言,我会将模式命名为符合常规标识符命名规则,而不是使用数字 TenantId 作为模式名称。我个人会将所有数据以 ([COUNT] INT NOT NULL, [TableName] NVARCHAR(MAX) NOT NULL) 的形式插入到一个存储表中,如下所示。然后,您可以使用 PIVOT 如下所示获取每个表的值。
顺便说一句,还请注意 QUOTENAME 函数的使用——如果表作为变量传入,这将确保您的代码不会受到 SQL 注入的攻击(我希望简单地提供表名列表并拥有它亲自动态地运行它们 - 很高兴将其写出来并提供作为答案,如果你愿意的话)。
dbfiddle 重现
如果您使用的是 SQL Server 2012 或更高版本,您也可以只使用
WITH RESULT SETS
您的EXEC
: