尝试使用动态透视查询时出现语法错误

Posted

技术标签:

【中文标题】尝试使用动态透视查询时出现语法错误【英文标题】:Syntax Error when trying to use Dynamic Pivot Query 【发布时间】:2021-09-18 09:41:26 【问题描述】:

我已经玩了一段时间的 PIVOT 功能。我有一张像这样的表

IdPersona IdEstadoSocio Periodo
-------------------------------
1044659   6             2021-06
721396    5             2021-06
219886    6             2021-06
1906611   7             2021-06
1027906   2             2021-06

每个 ClientID 每个月都会重复一次。每个月都会将新行添加到表中,并带有与该行关联的新期间。这是一个递增表。

我需要做的是 PIVOT 表,所以它基本上是这样结束的:

IdPersona 2021-01 2021-02 2021-03 2021-04 
----------------------------------------
1044659  6       3       1       4
721396   5       5       2       6 
219886   6       6       4       1
1906611  7       7       9       2 
1027906  2       1       1       1

当然,我希望我的代码是动态的。我不想每个月都harcode,比如:

    SELECT *
FROM [fid].[FACT_Socios_Resumen_Periodo]
PIVOT(MAX(IdEstadoSocio) 
      FOR [Periodo] IN ([2021-01], [2021-02], [2021-03], [2021-04], [2021-05], [2021-06])) AS PVTTable

所以我一直在尝试在这里找到的几种动态解决方案,但没有一个对我有用,我不知道为什么。这让我发疯了。

This solutions给我

“FOR”附近的语法不正确

我的代码如下:

DECLARE @cols AS NVARCHAR(MAX),@query  AS NVARCHAR(MAX);

SET @cols = STUFF((SELECT DISTINCT ',' + QUOTENAME(periodo) 
            FROM [fid].[FACT_Socios_Resumen_Periodo]
            FOR XML PATH(''), TYPE
            ).value('.', 'NVARCHAR(MAX)') 
        ,1,1,'')

set @query = 'SELECT IdPersona, ' + @cols + ' from 
            (
                select IdPersona
                    , IdEstadoSocio
                    , periodo
                from [fid].[FACT_Socios_Resumen_Periodo]
           ) x
            pivot 
            (
                 max(IdEstadoSocio)
                for periodo in (' + @cols + ')
            ) p '

execute(@query)

同一链接中提供的second solution 给了我

在 SELECT 语句中分配的变量不能 与 a 一起使用时包含在表达式或赋值中 from 子句。

这有点可以理解,因为据我了解,查询试图以递归方式解决获取 [Period] 的 DISTINCT 值的问题。但是,每个人也都认为这是一个可行的答案。

我的代码如下:

DECLARE @cols  AS NVARCHAR(MAX)='';
DECLARE @query AS NVARCHAR(MAX)='';

SELECT @cols = @cols + QUOTENAME(periodo) + ',' FROM (select distinct periodo from [fid].[FACT_Socios_Resumen_Periodo] ) as tmp
select @cols = substring(@cols, 0, len(@cols)) --trim "," at end

set @query = 
'SELECT * from 
(
    select idpersona, idestadosocio, periodo from [fid].[FACT_Socios_Resumen_Periodo]
) src
pivot 
(
    max(idestadosocio) for periodo in (' + @cols + ')
) piv'

execute(@query)

我试过的third solution 给了我上面提到的相同错误,语法相似但不完全相同。它尝试递归地求解 DISTINCT [Period]。

我的代码如下:

DECLARE @DynamicPivotQuery AS NVARCHAR(MAX)
DECLARE @ColumnName AS NVARCHAR(MAX)

--Get distinct values of the PIVOT Column 
SELECT @ColumnName = ISNULL(@ColumnName + ',', '') + QUOTENAME(periodo)
FROM (SELECT DISTINCT periodo FROM [fid].[FACT_Socios_Resumen_Periodo]) AS Periodos
 
--Prepare the PIVOT query using the dynamic 
SET @DynamicPivotQuery = 
  N'SELECT IdPersona, ' + @ColumnName + '
    FROM [fid].[FACT_Socios_Resumen_Periodo]
    PIVOT(MAX(IdEstadoSocio) 
          FOR periodo IN (' + @ColumnName + ')) AS PVTTable'
--Execute the Dynamic Pivot Query
EXEC sp_executesql @DynamicPivotQuery

那么,我到底做错了什么?有人可以给我一个提示吗?我失败了整个社区批准的解决方案,我不明白为什么。我基本上试图理解代码,复制它,并替换列和表。只是。我没有再做任何改变。提前致谢!

【问题讨论】:

完成!我的错。这么久第一次发帖,不好意思 我检查了您发布的三个代码段,没有错误。我认为你做得对。 【参考方案1】:

查看您的第三个解决方案。

我注意到的第一件事是,当您进行连接时,您没有合并 @ColumnName 的初始空值。

SELECT @ColumnName = Isnull(@ColumnName + ',', '') + QUOTENAME(periodo)
FROM (SELECT DISTINCT periodo FROM [fid].[FACT_Socios_Resumen_Periodo]) AS Periodos

这应该可以解决您的问题。

如果您在执行之前打印结果@ColumnName 和@DynamicPivotQuery,它通常会告诉您问题出在哪里。

对于不支持SELECT @Variable的sql版本

SQL Azure 和 SQL DW 仅支持在设置变量值时使用 SET。 您可以在这些服务器上使用STRING_AGG()

set @ColumnName = (select string_agg(QUOTENAME(periodo),',') from (select distinct periodo from FACT_Socios_Resumen_Periodo) t)

【讨论】:

你是对的。但这只是我忘记在上面的代码中复制的东西。我尝试了与提供的链接完全相同的解决方案。如果您检查,您会发现原作者使用 ISNULL 来解决您提到的这个确切问题。尽管如此,问题仍然存在,我仍然得到“与 from 子句结合使用时,在 SELECT 语句中分配的变量不能包含在表达式或赋值中。” 另外,有一点需要澄清。我无法打印这两个变量的结果,因为查询在到达该点之前失败。我尝试删除 @Columnname + ',' 语句,并且查询确实有效。然而,它只列出了它找到的第一个 [Period],并没有“累积”所有找到的 [Period] 你是说在你到达EXEC sp_executesql @DynamicPivotQuery之前查询就失败了? 您的示例图片和查询不匹配(列名)。如果我们没有正确的架构,那就更难提供帮助了。 如果您有新版本,您可能需要使用 STRING_AGG set @ColumnName = (select string_agg(QUOTENAME(periodo),',') from (select distinct periodo from FACT_Socios_Resumen_Periodo) t)

以上是关于尝试使用动态透视查询时出现语法错误的主要内容,如果未能解决你的问题,请参考以下文章

使用 OleDb 插入访问时出现语法错误

在mysql查询中使用参数时出现mysql语法错误

当我尝试在 mysql 中创建触发器时出现语法错误

对指定 VALUE 使用 UPDATE 时出现 Amazon Redshift 语法错误

尝试使用 if 语句创建函数时出现 Postgresql 语法错误

尝试在重复上使用时出现语法错误