我有一个相当长的存储过程(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 个字符。
关于我做错了什么有什么想法吗?
所以这里有两个独立且不相关的错误,所以我将依次讨论每个错误。
第一个错误:
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
,我认为这也应该修复。