从结束逗号中删除最后一个动态列?

Strip the last dynamic column from ending comma?

我正在编写以下动态 SQL,并在 FROM 关键字周围出现错误。

Incorrect syntax near the keyword 'FROM'.

  ' + @columnList + '
FROM [History] 

我知道为什么,因为它前面不应该有逗号。但是,由于它前面的列 (@columnList) 是动态 SQL 的结果,我该如何解决这个问题?

基本上,我需要一种方法来制作

SELECT @columnList =....

不在最后选择的 column/Account 末尾附加逗号。

这部分最后加逗号:

quotename(AccTbl.Account), ',',

完整查询:

DECLARE @sqlCommand NVARCHAR(MAX) = '',
        @columnList NVARCHAR(MAX) = '',
        @pivotColumns NVARCHAR(MAX) = '';

SELECT @columnList =
  (SELECT DISTINCT concat(CHAR(9), 'COALESCE(', quotename(AccTbl.Account), ', 0)', quotename(AccTbl.Account), ',', CHAR(10)) --CHAR(9) & CHAR(10) for indentation/formatting
   FROM [Accounts] AccTbl
   WHERE AccTbl.Account NOT IN ('WS')
   FOR XML Path(''), TYPE).value('(./text())[1]', 'NVARCHAR(MAX)');

SELECT @pivotColumns = STUFF(
   (SELECT DISTINCT concat(CHAR(9), ',', quotename(AccTbl.Account), CHAR(10))
    FROM [Accounts] AccTbl
    WHERE AccTbl.Account NOT IN ('WS')
    FOR XML Path(''), TYPE).value('(./text())[1]', 'NVARCHAR(MAX)'), 1, 1, '');

/*
EXEC the sqlCommand as separate batches to prevent this error: 'CREATE VIEW' must be the first statement in a query batch.

*/

SET @sqlCommand = '
    USE [ABC_DB]
    --GO
    DROP VIEW IF EXISTS [dbo].[Piv];
    --GO
    SET ANSI_NULLS ON
    --GO
    SET QUOTED_IDENTIFIER ON
    --GO
';

Execute sp_executesql @sqlCommand;

SET @sqlCommand = '
    CREATE VIEW [dbo].[Piv]
    AS
    (SELECT
      [Style Code],
      ' + @columnList + '
    FROM [History] 
        PIVOT (SUM([Value]) FOR [Accounts] IN (
            ' + @pivotColumns + '
            )
        ) 
    AS Piv);
';

PRINT @sqlCommand;
Execute sp_executesql @sqlCommand;

换句话说,现在发生的事情是这样的:

更新:

@columnList 固定为前导逗号而不是尾随逗号,但前导逗号和尾随逗号都适用于 @pivotColumns,因为我们在 PIVOT 部分没有预先存在的列查询就像我们在 SELECT 语句中使用 Style Code.

逗号不要放在末尾,放在开头,然后去掉第一个字符,使用STUFF,在T-SQL.[=14中就容易多了=]

所以 {Expression} + ',' 改为 ',' + {Expression}。然后你可以简单地做 STUFF(@columnList,1,1,'') 来删除 leading 逗号。

部分问题是您的 'formatting' 代码。一般来说,我同意格式化动态代码有助于调试 - 在这里它会妨碍。

SELECT @columnList = STUFF(
  (SELECT DISTINCT concat(', ', quotename(AccTbl.Account))
   FROM [Accounts] AccTbl
   WHERE AccTbl.Account NOT IN ('WS')
   FOR XML Path(''), TYPE).value('(./text())[1]', 'NVARCHAR(MAX)'), 1, 1, '');

SELECT @pivotColumns = STUFF(
   (SELECT DISTINCT concat(', ', quotename(AccTbl.Account))
    FROM [Accounts] AccTbl
    WHERE AccTbl.Account NOT IN ('WS')
    FOR XML Path(''), TYPE).value('(./text())[1]', 'NVARCHAR(MAX)'), 1, 1, '');

删除那些 - 我们看到两个语句完全相同。假设来自帐户 table 的结果是:Acct1、Acct2

@columnList 和@pivotColumns 的结果都是“[Acct1], [Acct2]”。所以 - 如果您想扩展列列表部分,例如添加 table 别名(我会这样做):

SELECT @columnList = STUFF(
  (SELECT DISTINCT concat(', ', 'h.', quotename(AccTbl.Account))
   FROM [Accounts] AccTbl
   WHERE AccTbl.Account NOT IN ('WS')
   FOR XML Path(''), TYPE).value('(./text())[1]', 'NVARCHAR(MAX)'), 1, 1, '');

我不会费心在最终结果中格式化这些列,因为您将根据需要使用动态 SQL.

重新创建视图
SET @sqlCommand = '
    CREATE VIEW [dbo].[Piv]
    AS
    (SELECT
      h.[Style Code],
      ' + @columnList + '
    FROM [History] h
        PIVOT (SUM(h.[Value]) FOR [Accounts] IN (
            ' + @pivotColumns + '
            )
        ) 
    AS Piv);
';