AskOverflow.Dev

AskOverflow.Dev Logo AskOverflow.Dev Logo

AskOverflow.Dev Navigation

  • Início
  • system&network
  • Ubuntu
  • Unix
  • DBA
  • Computer
  • Coding
  • LangChain

Mobile menu

Close
  • Início
  • system&network
    • Recentes
    • Highest score
    • tags
  • Ubuntu
    • Recentes
    • Highest score
    • tags
  • Unix
    • Recentes
    • tags
  • DBA
    • Recentes
    • tags
  • Computer
    • Recentes
    • tags
  • Coding
    • Recentes
    • tags
Início / dba / Perguntas / 232238
Accepted
Tom_W
Tom_W
Asked: 2019-03-16 02:47:13 +0800 CST2019-03-16 02:47:13 +0800 CST 2019-03-16 02:47:13 +0800 CST

Dando EXEC (@Variable) um nome de coluna e concatenação

  • 772

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

Imagina 1

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

sql-server
  • 4 4 respostas
  • 361 Views

4 respostas

  • Voted
  1. Best Answer
    EzLo
    2019-03-16T03:13:00+08:002019-03-16T03:13:00+08:00

    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 ALLe PIVOTobter 1 linha com 3 colunas, tudo dentro do SQL dinâmico.

    Altere esta parte:

    DECLARE @OrphanAuditItems NVARCHAR(MAX)
    DECLARE @OrphanAuditAnswers NVARCHAR(MAX) 
    DECLARE @OrphanAuditQuestion NVARCHAR(MAX)
    
    --.....
    
    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)
    

    Por esta:

    DECLARE @DynamicSQL NVARCHAR(MAX) = N'
        ;WITH PrePivot AS
        (
            SELECT 
                Amount = COUNT(*),
                Type = ''OrphanAuditItems''
            FROM 
                [Dynamic].['+ CAST (@TenantId AS NVARCHAR) +'].[AuditItems] 
            WHERE 
                FK_Audit NOT IN (SELECT SystemID FROM [Dynamic].['+ CAST (@TenantId AS NVARCHAR) +'].[Audits]) 
    
            UNION ALL
    
            SELECT 
                Amount = COUNT(*),
                Type = ''OrphanAuditAnswers''
            FROM 
                [Dynamic].['+ CAST (@TenantId AS NVARCHAR) +'].[AuditAnswers] 
            WHERE 
                AuditItemId NOT IN (SELECT SystemID FROM [Dynamic].['+ CAST (@TenantId AS NVARCHAR) +'].[AuditItems])
    
            UNION ALL
    
            SELECT 
                Amount = COUNT(*),
                Type = ''OrphanAuditQuestion''
            FROM 
                [Dynamic].['+ CAST (@TenantId AS NVARCHAR) +'].[AuditQuestion] 
            WHERE 
                AuditId NOT IN (SELECT SystemID FROM [Dynamic].['+ CAST (@TenantId AS NVARCHAR) +'].[Audits]) 
        )
        SELECT
            P.OrphanAuditItems,
            P.OrphanAuditAnswers,
            P.OrphanAuditQuestion
        FROM
            PrePivot AS T
            PIVOT (
                MAX(T.Amount) FOR T.Type IN ([OrphanAuditItems], [OrphanAuditAnswers], [OrphanAuditQuestion])
            ) AS P '
    
    -- PRINT (@DynamicSQL)
    EXEC (@DynamicSQL)
    

    Certifique-se de usar o PRINTpara validar o SQL resultante antes de executar oEXEC .


    Outra solução é recuperar os valores em variáveis, usando sp_executesqlcom OUTPUTparâmetros:

    -- Items
    DECLARE @OrphanAuditItems INT
    
    DECLARE @DynamicSQL NVARCHAR(MAX) = N'
        SELECT
            @OrphanAuditItems = COUNT(*)
        FROM
            #OrphanResults AS O
            CROSS JOIN [Dynamic].['+ CAST (@TenantId AS NVARCHAR) +'].[AuditItems]
        WHERE 
            FK_Audit NOT IN (SELECT SystemID FROM [Dynamic].['+ CAST (@TenantId AS NVARCHAR) +'].[Audits])'
    
    EXEC sp_executesql 
        @stmt = @DynamicSQL,
        @params = N'@OrphanAuditItems INT OUTPUT',
        @OrphanAuditItems = @OrphanAuditItems OUTPUT
    
    
    -- Answers
    DECLARE @OrphanAuditAnswers INT
    
    SET @DynamicSQL = N'
        SELECT 
            @OrphanAuditAnswers = COUNT(*) 
        FROM 
            [Dynamic].['+ CAST (@TenantId AS NVARCHAR) +'].[AuditAnswers] 
        WHERE 
            AuditItemId NOT IN (SELECT SystemID FROM [Dynamic].['+ CAST (@TenantId AS NVARCHAR) +'].[AuditItems])'
    
    EXEC sp_executesql 
        @stmt = @DynamicSQL,
        @params = N'@OrphanAuditAnswers INT OUTPUT',
        @OrphanAuditAnswers = @OrphanAuditAnswers OUTPUT
    
    
    -- Questions
    DECLARE @OrphanAuditQuestion INT
    
    SET @DynamicSQL = N'
        SELECT 
            @OrphanAuditQuestion = COUNT(*) 
        FROM 
            [Dynamic].['+ CAST (@TenantId AS NVARCHAR) +'].[AuditQuestion] 
        WHERE 
            AuditId NOT IN (SELECT SystemID FROM [Dynamic].['+ CAST (@TenantId AS NVARCHAR) +'].[Audits])'
    
    EXEC sp_executesql 
        @stmt = @DynamicSQL,
        @params = N'@OrphanAuditQuestion INT OUTPUT',
        @OrphanAuditQuestion = @OrphanAuditQuestion OUTPUT
    
    SELECT
        OrphanAuditItems = @OrphanAuditItems,
        OrphanAuditAnswers = @OrphanAuditAnswers,
        OrphanAuditQuestion = @OrphanAuditQuestion
    

    Acho o último um pouco mais flexível e legível do que o primeiro.

    • 3
  2. Dan Guzman
    2019-03-16T03:23:43+08:002019-03-16T03:23:43+08:00

    Um método é com subconsultas para cada coluna. O exemplo abaixo também usa QUOTENAMEpara 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.

    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 @OrphanAuditData 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 @OrphanAuditData = N'SELECT
        (SELECT COUNT(*) 
            FROM [Dynamic].' + QUOTENAME(CAST(@TenantId AS NVARCHAR)) + '.[AuditItems] 
            WHERE FK_Audit NOT IN (SELECT SystemID FROM [Dynamic].' + QUOTENAME(CAST(@TenantId AS NVARCHAR)) + '.[Audits])) AS OrphanAuditItems
    '
    + N'    ,(SELECT COUNT(*)
            FROM [Dynamic].'+ QUOTENAME(CAST(@TenantId AS NVARCHAR)) + '.[AuditAnswers] 
            WHERE AuditItemId NOT IN (SELECT SystemID FROM [Dynamic].' + QUOTENAME(CAST(@TenantId AS NVARCHAR)) + '.[AuditItems])) AS OrphanAuditAnswers
    '
    + N'    ,(SELECT COUNT(*)
            FROM [Dynamic].'+ QUOTENAME(CAST(@TenantId AS NVARCHAR)) + '.[AuditQuestion] 
            WHERE AuditId NOT IN (SELECT SystemID FROM [Dynamic].'+ QUOTENAME(CAST(@TenantId AS NVARCHAR)) + '].[Audits])) AS OrphanAuditQuestion;'
    
    EXEC (@OrphanAuditData);
    
    END;
    GO
    
    • 2
  3. George.Palacios
    2019-03-16T03:15:32+08:002019-03-16T03:15:32+08:00

    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).

    CREATE TABLE #Datas (ID INT);
    
    INSERT INTO #Datas
    (
        ID
    )
    VALUES
    ( 1  -- ID - int
        )
        GO
    
    DECLARE @SQL1 NVARCHAR(MAX) = 'SELECT COUNT(1), ''TableName1'' FROM ' + QUOTENAME('#Datas') + ';'
    DECLARE @SQL2 NVARCHAR(MAX) = 'SELECT COUNT(1), ''TableName2'' FROM ' + QUOTENAME('#Datas') + ';'
    DECLARE @SQL3 NVARCHAR(MAX) = 'SELECT COUNT(1), ''TableName3'' FROM ' + QUOTENAME('#Datas') + ';'
    
    CREATE TABLE #Counts (Cnt INT, Tbl NVARCHAR(MAX));
    
    INSERT INTO #Counts
    EXEC (@SQL1);
    
    INSERT INTO #Counts
    EXEC (@SQL2);
    
    INSERT INTO #Counts
    EXEC (@SQL3);
    
    SELECT * FROM #Counts
    
    PIVOT (SUM(Cnt) FOR Tbl IN ([TableName1],[TableName2],[TableName3])) AS d
    
    DROP TABLE #Datas;
    DROP TABLE #Counts
    

    reprodução do dbfiddle

    • 0
  4. Jason Whitish
    2019-03-16T11:36:10+08:002019-03-16T11:36:10+08:00

    Se você estiver usando o SQL Server 2012 ou posterior, também poderá usar WITH RESULT SETScom seu EXEC:

    exec (N'select 1') 
    WITH RESULT SETS
    (
        (
            ID int
        )
    )
    

    Conjunto de resultados

    • 0

relate perguntas

  • SQL Server - Como as páginas de dados são armazenadas ao usar um índice clusterizado

  • Preciso de índices separados para cada tipo de consulta ou um índice de várias colunas funcionará?

  • Quando devo usar uma restrição exclusiva em vez de um índice exclusivo?

  • Quais são as principais causas de deadlocks e podem ser evitadas?

  • Como determinar se um Índice é necessário ou necessário

Sidebar

Stats

  • Perguntas 205573
  • respostas 270741
  • best respostas 135370
  • utilizador 68524
  • Highest score
  • respostas
  • Marko Smith

    conectar ao servidor PostgreSQL: FATAL: nenhuma entrada pg_hba.conf para o host

    • 12 respostas
  • Marko Smith

    Como fazer a saída do sqlplus aparecer em uma linha?

    • 3 respostas
  • Marko Smith

    Selecione qual tem data máxima ou data mais recente

    • 3 respostas
  • Marko Smith

    Como faço para listar todos os esquemas no PostgreSQL?

    • 4 respostas
  • Marko Smith

    Listar todas as colunas de uma tabela especificada

    • 5 respostas
  • Marko Smith

    Como usar o sqlplus para se conectar a um banco de dados Oracle localizado em outro host sem modificar meu próprio tnsnames.ora

    • 4 respostas
  • Marko Smith

    Como você mysqldump tabela (s) específica (s)?

    • 4 respostas
  • Marko Smith

    Listar os privilégios do banco de dados usando o psql

    • 10 respostas
  • Marko Smith

    Como inserir valores em uma tabela de uma consulta de seleção no PostgreSQL?

    • 4 respostas
  • Marko Smith

    Como faço para listar todos os bancos de dados e tabelas usando o psql?

    • 7 respostas
  • Martin Hope
    Jin conectar ao servidor PostgreSQL: FATAL: nenhuma entrada pg_hba.conf para o host 2014-12-02 02:54:58 +0800 CST
  • Martin Hope
    Stéphane Como faço para listar todos os esquemas no PostgreSQL? 2013-04-16 11:19:16 +0800 CST
  • Martin Hope
    Mike Walsh Por que o log de transações continua crescendo ou fica sem espaço? 2012-12-05 18:11:22 +0800 CST
  • Martin Hope
    Stephane Rolland Listar todas as colunas de uma tabela especificada 2012-08-14 04:44:44 +0800 CST
  • Martin Hope
    haxney O MySQL pode realizar consultas razoavelmente em bilhões de linhas? 2012-07-03 11:36:13 +0800 CST
  • Martin Hope
    qazwsx Como posso monitorar o andamento de uma importação de um arquivo .sql grande? 2012-05-03 08:54:41 +0800 CST
  • Martin Hope
    markdorison Como você mysqldump tabela (s) específica (s)? 2011-12-17 12:39:37 +0800 CST
  • Martin Hope
    Jonas Como posso cronometrar consultas SQL usando psql? 2011-06-04 02:22:54 +0800 CST
  • Martin Hope
    Jonas Como inserir valores em uma tabela de uma consulta de seleção no PostgreSQL? 2011-05-28 00:33:05 +0800 CST
  • Martin Hope
    Jonas Como faço para listar todos os bancos de dados e tabelas usando o psql? 2011-02-18 00:45:49 +0800 CST

Hot tag

sql-server mysql postgresql sql-server-2014 sql-server-2016 oracle sql-server-2008 database-design query-performance sql-server-2017

Explore

  • Início
  • Perguntas
    • Recentes
    • Highest score
  • tag
  • help

Footer

AskOverflow.Dev

About Us

  • About Us
  • Contact Us

Legal Stuff

  • Privacy Policy

Language

  • Pt
  • Server
  • Unix

© 2023 AskOverflow.DEV All Rights Reserve