【问题标题】:Strip the last dynamic column from ending comma?从结束逗号中删除最后一个动态列?
【发布时间】:2021-06-27 17:51:46
【问题描述】:

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

关键字“FROM”附近的语法不正确。

  ' + @columnList + '
FROM [History] 

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

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

SELECT @columnList =....

不要在最后选择的最后一列/帐户的末尾附加逗号。

在此部分末尾添加逗号:

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.
https://stackoverflow.com/a/39135516/8397835
*/

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 部分中没有预先存在的列,就像我们在Style Code 的 SELECT 语句。

【问题讨论】:

  • 您还附加了一个选项卡,因此您需要将STUFF 参数设置为, 1, 2, ''),如果可以的话,我强烈建议您使用STRING_AGG。此外,那些USESET 命令需要在下一个查询中重复,它们仅适用于该范围。
  • @Charlieface 我考虑过使用STRING AGG,但我有 sql server 2016 :( 另外,我什至需要那些 USE 和 SET 吗?我发现无论我手动创建视图,它们都会自动生成. 但是,我将它们放在单独的范围内的原因是因为我收到一个错误,即 CREATE VIEW 需要成为批处理中的第一个语句,并且一个 SO 答案建议将它们分成单独的批处理

标签: sql sql-server tsql dynamic-sql


【解决方案1】:

不要把逗号放在末尾,把它们放在开头,然后去掉第一个字符,使用STUFF,这在 T-SQL 中要容易得多。

因此,不要使用{Expression} + ',',而是使用',' + {Expression}。然后您可以简单地使用STUFF(@columnList,1,1,'') 来删除前导逗号。

【讨论】:

  • “哦,这是个好主意!”确实意识到你已经在为@pivotColumns做这些了,对吧......?不要盲目地从互联网上复制和粘贴解决方案(我认为这就是你有混合逻辑的原因),花点时间了解他们在做什么。
  • 我确实意识到这就是我说好主意的原因,因为我确实有 @pivotColumns 这样做。我认为我为@columnList 选择不同方式的原因是因为我当前的视图末尾有逗号,所以这就是为什么我在@columnList 末尾添加了逗号。这是我大脑冻结片刻的那些时刻之一。我确切地知道发生了什么,因为我围绕 STUFF 进行了大量研究以了解到底发生了什么。实际上,我知道有更好的方法来做到这一点STRING AGG 但需要 2017 年,我目前只有 2016 年/跨度>
  • 好的,现在我遇到了@pivotColumns 的问题。第一列有一个前导逗号,在这部分FOR [Accounts] IN ( ' + @pivotColumns + ',不应该是这种情况,如果我像我最初为@columnList 那样使用逗号尾随,它最后也会成为一个问题
  • 我不明白。您将逗号放在开头,然后删除第一个逗号。这就是解决方案,@Cataster。我无法运行您的 SQL,因此无法复制您的问题;我无权访问您的实例。如果开头和结尾都有逗号,是不是忘了去掉末尾的逗号?
  • 所以基本上,我在@columnList 上遇到的问题已经得到解决,这要归功于领先的逗号建议。然而,既然视图查询的那部分是正确的,我在查询的第二部分得到错误,也是由于逗号。请检查我的帖子更新
【解决方案2】:

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

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, '');

删除那些 - 我们看到两个语句完全相同。假设 Accounts 表的结果是:Acct1, Acct2

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

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);
';

【讨论】:

  • 这些列表并不完全相同,因为@columnList 也前置了COALESCE。顺便说一句,欢迎来到 stackoverflow!
  • 即使使用表别名,在 PIVOT 部分也没有解决前导逗号问题
猜你喜欢
  • 2015-07-23
  • 1970-01-01
  • 1970-01-01
  • 2016-06-28
  • 1970-01-01
  • 1970-01-01
  • 2013-11-24
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多