如何编写一个包含SQL服务器端模块(Stored Procedure)的动态SQL代码来创建文件?

How to write a SQL server-side module (Stored Procedure) containing the dynamic SQL code to create documents?

我写了一个包含动态的存储过程SQL来创建指定格式的文件。 文档是针对销售区域还是针对销售人员,将在 运行 时确定,因为它是动态的 SQL。

销售区域文件:

{"TerritoryID":1,"TotalYearlySales":[2620944,5325813,6759501,3355403]},  
{"TerritoryID":2,"TotalYearlySales":[705672,3272240,2965567,876731]} 

销售人员的文件:

{"SalesPersonID":274, "TotalYearlySales":[32568,516197,485881,201289]},     
{"SalesPersonID":275, "TotalYearlySales":[986298,3806298,4490942,1191828]}    

文档中的数据来自AdventureWorks

create procedure dbo.TotalYearlySales
    @id nvarchar(30)
as
begin
    set @id = cast (@id as varchar(30))
    SELECT DISTINCT @id,
            JSON_QUERY('[' +
                STUFF(
                    (SELECT ',', rtrim(cast(SUM(TotalDue) as int))
                     FROM Sales.SalesOrderHeader SOH2
                     WHERE SOH1.@id = SOH2.@id 
                     AND SOH2.@id is not null
                     GROUP BY YEAR(SOH2.OrderDate)
                     ORDER BY YEAR(SOH2.OrderDate)
                     FOR XML PATH(''))
                , 1, 1, '')
            + ']') as TotalYearlySales
    from Sales.SalesOrderHeader SOH1
    GROUP BY cast (@id as varchar(30))
    ORDER BY cast (@id as varchar(30))
    FOR JSON AUTO;
end



    
declare @MyInput varchar(20);
set @MyInput= 'TerritoryID';
exec dbo.TotalYearlySales @MyInput;

此 SP 无法正常工作,因为我无法传递 @id,我收到一条错误消息 Incorrect syntax near '@id'。请告诉我如何使用动态 SQL 语句编写存储过程。

我正在使用 SQL Server 2019

如果我对问题的理解正确,您需要针对不同的分组标准(TerritoryIDSalesPersonID)构建并执行动态语句。

基于问题中的尝试,一种可能的方法是以下存储过程。请注意,从 SQL Server 2017 开始,您可以使用 STRING_AGG()(而不是 FOR XML PATH)进行字符串聚合:

CREATE PROCEDURE dbo.TotalYearlySales
   @id sysname
AS
BEGIN
   DECLARE @stm nvarchar(max)
   DECLARE @err int
   
   -- Dynamic statement
   SET @stm = 
      N'SELECT t.' + QUOTENAME(@id) + N', CONCAT(''['', STRING_AGG(t.TotalDue, '',''), '']'') AS TotalYearlySales ' +
      N'FROM ( ' +
         N'SELECT ' + QUOTENAME(@id) + N', CONVERT(int, SUM(TotalDue)) AS TotalDue ' +
         N'FROM Sales.SalesOrderHeader ' +
         N'WHERE ' + QUOTENAME(@id) + N' IS NOT NULL ' +
         N'GROUP BY ' + QUOTENAME(@id) + N', YEAR(OrderDate) ' +
      N') t ' +
      N'GROUP BY t.' + QUOTENAME(@id) + N' ' +
      N'FOR JSON AUTO, WITHOUT_ARRAY_WRAPPER'

   -- Statement execution
   EXEC @err = sp_executesql @stm, N' @id sysname', @id
   IF @err <> 0 BEGIN
      PRINT 'Error' 
   END
END

执行:

DECLARE @MyInput sysname
SET @MyInput = N'TerritoryID';
EXEC dbo.TotalYearlySales @MyInput