如何编写包含动态SQL代码的SQL server端模块(存储过程)来创建文档?

如何编写包含动态SQL代码的SQL server端模块(存储过程)来创建文档?,sql,sql-server,stored-procedures,dynamic-sql,sql-server-2019,Sql,Sql Server,Stored Procedures,Dynamic Sql,Sql Server 2019,我编写了一个包含动态SQL的存储过程来创建指定格式的文档。 文档是针对销售区域还是针对销售人员,将在运行时确定,因为它是动态SQL 销售区域的文件: {"TerritoryID":1,"TotalYearlySales":[2620944,5325813,6759501,3355403]}, {"TerritoryID":2,"TotalYearlySales":[705672,3272240,2965567,8

我编写了一个包含动态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

创建过程dbo.TotalYearlySales @id nvarchar30 像 开始 将@id=cast@id设置为varchar30 选择DISTINCT@id, JSON_查询'['+ 东西 选择“,”rtrimcastSUMTotalDue作为int 来自Sales.SalesOrderHeader SOH2 其中SOH1@id=SOH2@id 和SOH2。@id不为空 按年份分组2.OrderDate 按年份订购2.OrderDate 对于XML路径 , 1, 1, +“]”作为全年销售总额 来自Sales.SalesOrderHeader SOH1 按cast@id作为varchar30分组 通过铸造@id作为varchar30订购 对于JSON AUTO; 终止 声明@MyInput varchar20; 设置@MyInput='TerritoryID'; exec dbo.TotalYearlySales@MyInput; 此SP无法工作,因为我无法传递@id,我在“@id”附近收到一个错误,语法不正确。请告诉我如何使用动态SQL语句编写存储过程


我正在使用SQL Server 2019

如果我正确理解了这个问题,您需要为不同的分组标准TerritoryID和SalesorsOnId构建并执行动态语句

根据问题中的尝试,一种可能的方法是以下存储过程。请注意,从SQL Server 2017开始,您可以使用STRING_AGG代替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

如果我正确理解了这个问题,您需要为不同的分组标准TerritoryID和SalesorsOnId构建并执行动态语句

根据问题中的尝试,一种可能的方法是以下存储过程。请注意,从SQL Server 2017开始,您可以使用STRING_AGG代替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

您好@Zhorov我使用的是SQL Server 2019,这不是动态SQL。动态sql是使用代码构建包含要运行的静态sql的变量,然后使用sp_executesql执行它。我建议阅读有关动态sql online的文章,然后再回来找我们。如果销售区域或销售人员是唯一两个可能的选择,我建议完全避免使用动态sql。只需使用一个简单的if和两个版本的查询。顺便说一句,a=B和B不为null应该是a=B。null永远不等于null或=谓词中的任何内容。我猜具体的问题在于SOH1。@id-即使您有一个名为@id的列,在这种情况下,我强烈建议重命名它。您好@Zhorov,我使用的是SQL Server 2019,这不是动态sql。动态sql是使用代码构建包含要运行的静态sql的变量,然后使用sp_executesql执行它。我建议阅读有关动态sql online的文章,然后再回来找我们。如果销售区域或销售人员是唯一两个可能的选择,我建议完全避免使用动态sql。只需使用一个简单的if和两个版本的查询。顺便说一句,a=B和B不为null应该是a=B。null永远不等于null或=谓词中的任何内容。我猜具体的问题在于SOH1。@id-即使您有一个名为@id的列,在这种情况下,我强烈建议重命名它。