AskOverflow.Dev

AskOverflow.Dev Logo AskOverflow.Dev Logo

AskOverflow.Dev Navigation

  • 主页
  • 系统&网络
  • Ubuntu
  • Unix
  • DBA
  • Computer
  • Coding
  • LangChain

Mobile menu

Close
  • 主页
  • 系统&网络
    • 最新
    • 热门
    • 标签
  • Ubuntu
    • 最新
    • 热门
    • 标签
  • Unix
    • 最新
    • 标签
  • DBA
    • 最新
    • 标签
  • Computer
    • 最新
    • 标签
  • Coding
    • 最新
    • 标签
主页 / dba / 问题 / 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

给 EXEC (@Variable) 一个列名和连接

  • 772

我正在尝试编写一个存储过程,在我们的客户尝试升级之前检查孤立数据,因为孤立记录可能会导致问题。这是我到目前为止所拥有的;

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;

目前,这个脚本正在运行,但是输出是;

想象一下 1

我想在一行中返回结果,并让每一列都有自己的名称,例如:@OrphanAuditItems 结果显示为列名:OrphanAuditItems,等等。

实现这一目标的最佳方法是什么?

谢谢,汤姆

sql-server
  • 4 4 个回答
  • 361 Views

4 个回答

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

    您需要将 3 个动态 SQL 混合为 1 个返回 3 列,或者保留每个动态 SQL 但在最后混合它们的结果。有以下 2 种可能的解决方案:


    一种解决方案是使用UNION ALL和PIVOT来获取 1 行 3 列,所有这些都在动态 SQL 中。

    更改此部分:

    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)
    

    为了这:

    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)
    

    确保PRINT在执行之前使用 来验证生成的 SQL EXEC。


    sp_executesql另一种解决方案是使用withOUTPUT参数将值检索到变量中:

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

    我发现后者比第一个更灵活和可读。

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

    一种方法是对每一列使用子查询。下面的示例也使用QUOTENAME来包含标识符。就个人而言,我会将模式命名为符合常规标识符命名规则,而不是使用数字 TenantId 作为模式名称。

    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

    我个人会将所有数据以 ([COUNT] INT NOT NULL, [TableName] NVARCHAR(MAX) NOT NULL) 的形式插入到一个存储表中,如下所示。然后,您可以使用 PIVOT 如下所示获取每个表的值。

    顺便说一句,还请注意 QUOTENAME 函数的使用——如果表作为变量传入,这将确保您的代码不会受到 SQL 注入的攻击(我希望简单地提供表名列表并拥有它亲自动态地运行它们 - 很高兴将其写出来并提供作为答案,如果你愿意的话)。

    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
    

    dbfiddle 重现

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

    如果您使用的是 SQL Server 2012 或更高版本,您也可以只使用WITH RESULT SETS您的EXEC:

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

    结果集

    • 0

相关问题

  • SQL Server - 使用聚集索引时如何存储数据页

  • 我需要为每种类型的查询使用单独的索引,还是一个多列索引可以工作?

  • 什么时候应该使用唯一约束而不是唯一索引?

  • 死锁的主要原因是什么,可以预防吗?

  • 如何确定是否需要或需要索引

Sidebar

Stats

  • 问题 205573
  • 回答 270741
  • 最佳答案 135370
  • 用户 68524
  • 热门
  • 回答
  • Marko Smith

    连接到 PostgreSQL 服务器:致命:主机没有 pg_hba.conf 条目

    • 12 个回答
  • Marko Smith

    如何让sqlplus的输出出现在一行中?

    • 3 个回答
  • Marko Smith

    选择具有最大日期或最晚日期的日期

    • 3 个回答
  • Marko Smith

    如何列出 PostgreSQL 中的所有模式?

    • 4 个回答
  • Marko Smith

    列出指定表的所有列

    • 5 个回答
  • Marko Smith

    如何在不修改我自己的 tnsnames.ora 的情况下使用 sqlplus 连接到位于另一台主机上的 Oracle 数据库

    • 4 个回答
  • Marko Smith

    你如何mysqldump特定的表?

    • 4 个回答
  • Marko Smith

    使用 psql 列出数据库权限

    • 10 个回答
  • Marko Smith

    如何从 PostgreSQL 中的选择查询中将值插入表中?

    • 4 个回答
  • Marko Smith

    如何使用 psql 列出所有数据库和表?

    • 7 个回答
  • Martin Hope
    Jin 连接到 PostgreSQL 服务器:致命:主机没有 pg_hba.conf 条目 2014-12-02 02:54:58 +0800 CST
  • Martin Hope
    Stéphane 如何列出 PostgreSQL 中的所有模式? 2013-04-16 11:19:16 +0800 CST
  • Martin Hope
    Mike Walsh 为什么事务日志不断增长或空间不足? 2012-12-05 18:11:22 +0800 CST
  • Martin Hope
    Stephane Rolland 列出指定表的所有列 2012-08-14 04:44:44 +0800 CST
  • Martin Hope
    haxney MySQL 能否合理地对数十亿行执行查询? 2012-07-03 11:36:13 +0800 CST
  • Martin Hope
    qazwsx 如何监控大型 .sql 文件的导入进度? 2012-05-03 08:54:41 +0800 CST
  • Martin Hope
    markdorison 你如何mysqldump特定的表? 2011-12-17 12:39:37 +0800 CST
  • Martin Hope
    Jonas 如何使用 psql 对 SQL 查询进行计时? 2011-06-04 02:22:54 +0800 CST
  • Martin Hope
    Jonas 如何从 PostgreSQL 中的选择查询中将值插入表中? 2011-05-28 00:33:05 +0800 CST
  • Martin Hope
    Jonas 如何使用 psql 列出所有数据库和表? 2011-02-18 00:45:49 +0800 CST

热门标签

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

Explore

  • 主页
  • 问题
    • 最新
    • 热门
  • 标签
  • 帮助

Footer

AskOverflow.Dev

关于我们

  • 关于我们
  • 联系我们

Legal Stuff

  • Privacy Policy

Language

  • Pt
  • Server
  • Unix

© 2023 AskOverflow.DEV All Rights Reserve