使用 SQL 变量作为动态 SQL 的列标题

问题描述 投票:0回答:1

我有一个相当长的存储过程(MS SQL Server),业务用户询问是否可以使用存储在声明的变量中的值重命名列。

以下是在存储过程顶部声明的变量:

DECLARE @BeginDate  datetime = '12/31/23';
DECLARE @PlusBeginDate datetime = DATEADD(DAY,1,@BeginDate);
DECLARE @EndDate datetime = DATEADD(MONTH,120,EOMONTH(DATEADD(DAY,1,@PlusBeginDate)));
DECLARE @IncludePaidPortion bit = 0;
DECLARE @MonthAnnual char = 'M';
DECLARE @FinanceCompany varchar(max) = '1';
DECLARE @IncludeOnStream bit = 0;
DECLARE @TranCode varchar(max) = '1,35';
DECLARE @ContractBookType varchar(max) = 'capital';
DECLARE @FinanceProduct varchar(max) = '1,2,3';
DECLARE @IncludedStatus varchar(max) = '0';
DECLARE @IncludeTerminated bit = 0;
DECLARE @FundingSource varchar(max) = '0';
DECLARE @FinanceProgram varchar(max) = '20734';
DECLARE @ADC varchar(max) = '0';
DECLARE @IncludeResidual bit = 0;

它是一个更大的存储过程的一部分,但这是我关于动态 sql 的内容:

DECLARE @sqlQuery NVARCHAR(MAX);
    DECLARE @CaseDate datetime = '12/31/9999';

    SET @sqlQuery = '
    SELECT
        MAX(ContractId) as ContractId,
        MAX([Maturity Date]) as [Maturity Date],
        MAX([Extended Maturity Date]) as [Extended Maturity Date],
        @PlusBeginDate AS ReportBegin,
        @EndDate AS ReportEnd,
        SUM(PeriodCash1) as [' + QUOTENAME(@PeriodValue1) + '],
        SUM(PeriodCash2) as [' + QUOTENAME(@PeriodValue2) + ']
    FROM
                    (SELECT 
                        Cash.ContractOid
                        ,Cash.TransactionCodeOid
                        ,Cash.DueDate
                        ,ISNULL(Contract.ContractId,''N/A'') as ContractId
                        ,lc.AccountDistributionCodeOid
                        ,ContractTerm.MaturityDate as [Maturity Date]
                        ,CASE
                            WHEN ContractTerm.MaturityDate <> lc.[Maturity Date] 
                                THEN lc.[Maturity Date] 
                            ELSE ''''
                        END as [Extended Maturity Date]
                        ,CASE 
                            WHEN DueDate BETWEEN @PeriodBegin1 AND @PeriodEnd1 
                            AND DueDate <= ISNULL(Contract.TerminationDate,@CaseDate)
                                THEN Amount
                            ELSE 0  
                        END AS PeriodCash1      
                        ,CASE 
                            WHEN DueDate BETWEEN @PeriodBegin2 AND @PeriodEnd2
                            AND DueDate <= ISNULL(Contract.TerminationDate,@CaseDate)
                                THEN Amount
                            ELSE 0  
                        END AS PeriodCash2      
                    FROM #Cash Cash
                    INNER JOIN #LimitedContracts lc on lc.ContractOid = Cash.ContractOid
                    INNER JOIN dbo.Contract ON Cash.ContractOid = Contract.ContractOid
                    LEFT JOIN dbo.ContractTerm ON ContractTerm.ContractOid = Contract.ContractOid AND ContractTerm.IsPrimary = 1
                    inner join dbo.Product p on p.oid = ContractTerm.ProductOid
                    LEFT JOIN dbo.Entity FinComp ON FinComp.oid = Contract.CompanyOid   
                    LEFT JOIN dbo.Entity On Entity.oid = Contract.EntityOid  
                    LEFT JOIN dbo.Status ON Status.oid = Contract.StatusOid
                    LEFT JOIN dbo.TransactionCode ON TransactionCode.TransactionCodeOid = Cash.TransactionCodeOId
                    LEFT JOIN dbo.AccountDistributionCode ADC ON ADC.AccountDistributionCodeOid = lc.AccountDistributionCodeOid
                    ) SubQuery
            GROUP BY SubQuery.ContractOid, SubQuery.TransactionCodeOid
            ORDER BY ContractID';

    EXEC sp_executesql @sqlQuery;

由于某种原因,它返回以下错误: 消息 137,第 15 级,状态 2,第 6 行 必须声明标量变量“@PlusBeginDate”。 消息 103,第 15 级,状态 4,第 8 行 以“[January 2024]”开头的标识符, SUM(PeriodCash2) 为 [[2024 年 2 月] 从 (选择 C' 太长了。最大长度为 128。

如您所见,声明了 PlusBeginDate,如果我只运行动态 SQL 之前的所有内容,则不会发生此错误。

长度错误也没有多大意义,因为每个变量如下:“MONTH YYYY”永远不会接近 128 个字符。

关于我做错了什么有什么想法吗?

sql sql-server variables dynamic-sql
1个回答
0
投票

所以这里有两个独立且不相关的错误,所以我将依次讨论每个错误。

第一个错误:

Msg 137,Level 15,State 2,Line 6 必须声明标量变量“@PlusBeginDate”。

这是因为您使用的是在动态 SQL 范围之外声明的变量,但并未将其提供给动态 SQL。当您调用 sp_executesql 时,您必须显式传入这些参数,否则就像从未声明过它们一样。 因此,对于您的示例,您对 sp_executesql

的调用应该类似于

exec sp_exceutesql
    @sqlQuery,
    -- Variables you use within your dynamic sql
    N'@PeriodBegin1 date,
        @PeriodBegin2 date,
        @PlusBeginDate...
        ... <all other variables you are using within your dynamic sql',
    -- Variables outside your dynamic sql you want passed into your dynamic sql
    @PeriodBegin1,
    @PeriodBegin2,
    @PlusBeginDate...
    ... 
    /*
    <all the variables you want to pass into the procedure. use the same order as how you
    defined them in your parameters block>
    */

通过使动态 sql 在范围内包含这些值,第一个错误将消失。
第二个错误:

Msg 103,Level 15,State 4,Line 8 以 '[January 2024], SUM(PeriodCash2) as [[February 2024] FROM (SELECT C' 开头的标识符太长。最大长度为 128。

发生这种情况是因为您没有正确引用您的

@PeriodValue
。正确的语法是

' + quotename(@PeriodValue) + '

 
not
 
[' + quotename(@PeriodValue) + ']quotename
 适用于方括号的方式是转义(即加倍)字符串中的所有左方括号,将生成的语句包装在方括号中。然而,由于您在外部手动添加
另一个
级别的方括号,因此您将重新打开列名称括号,并且永远不会关闭它们。因此,它将 
quotename 部分之后的所有后续 SQL 视为列别名的一部分。由于列名不能超过 128 个字符,因此会引发该错误。
TL;DR,删除那些额外的方括号
quotename

,我认为这也应该修复。

© www.soinside.com 2019 - 2024. All rights reserved.