Estou tentando escrever um procedimento armazenado que verificará dados órfãos antes que nossos clientes tentem uma atualização, pois registros órfãos podem causar problemas. Isto é o que tenho até agora;
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;
No momento, este script está funcionando, porém a saída está;
Quero retornar os resultados em uma única linha e ter cada coluna com seu próprio nome, por exemplo: @OrphanAuditItems resultado mostra como nome da coluna: OrphanAuditItems e assim por diante.
Como é a melhor maneira de conseguir isso?
Obrigado, Tom
Você precisará misturar seus 3 SQLs dinâmicos em 1 que retorna 3 colunas, ou manter cada SQL dinâmico, mas misturar seu resultado no final. Existem 2 soluções possíveis a seguir:
Uma solução é usar
UNION ALL
ePIVOT
obter 1 linha com 3 colunas, tudo dentro do SQL dinâmico.Altere esta parte:
Por esta:
Certifique-se de usar o
PRINT
para validar o SQL resultante antes de executar oEXEC
.Outra solução é recuperar os valores em variáveis, usando
sp_executesql
comOUTPUT
parâmetros:Acho o último um pouco mais flexível e legível do que o primeiro.
Um método é com subconsultas para cada coluna. O exemplo abaixo também usa
QUOTENAME
para incluir identificadores. Pessoalmente, eu nomearia os esquemas de acordo com as regras regulares de nomenclatura do identificador, em vez de usar o TenantId numérico como o nome do esquema.Eu pessoalmente inseriria todos os dados em uma tabela de retenção na forma de ([COUNT] INT NOT NULL, [TableName] NVARCHAR(MAX) NOT NULL) conforme abaixo. Você pode então usar PIVOT conforme abaixo para obter os valores para cada tabela.
Como um aparte, observe também o uso da função QUOTENAME - isso garantirá que seu código não seja vulnerável à injeção de SQL se a tabela for passada como uma variável (eu procuraria simplesmente fornecer uma lista de nomes de tabelas e tê-la percorra todos eles dinamicamente pessoalmente - feliz em escrever isso e fornecer uma resposta, se desejar).
reprodução do dbfiddle
Se você estiver usando o SQL Server 2012 ou posterior, também poderá usar
WITH RESULT SETS
com seuEXEC
: