【问题标题】:Pivot using Dynamic SQL statement使用动态 SQL 语句进行透视
【发布时间】:2019-01-02 10:48:08
【问题描述】:

这是数据的一个小样本。在实际数据中,Name 和 Code 下的值有数百个,并且这些值经常变化。 因此,硬编码 Pivot 语句将不起作用。需要创建一个动态 SQL 语句 - 我需要帮助。

DECLARE @Test Table
(
  Name   Varchar(32),
  Code   Varchar(20)
)

INSERT INTO @Test(Name, Code) VALUES
  ('A-1', 'A-One')
, ('A 2', 'A-Two')
, ('B 1-b', 'B-One')
, ('B', 'A-Two')
, ('C', 'A-One')
, ('C', 'B-One')
, ('C', 'C-One')

样本数据集如下所示[再次强调,这只是一个小样本]:

Name    Code
A-1     A-One
A 1     A-Two
B 1-b   B-One
B       A-Two 
C       A-One
C       B-One
C       C-One

请注意,代码值 [如 A-One、A-Two 和 B-One] 可能与多个名称值相关联。

例如A-One 与名称 A-1 以及名称 C 一起出现...

我想输出它,所以它看起来像这样 [除了,有比我显示的更多的值 - 这些值可以改变]:

             A-1      A 1        B 1-b          B      C
A-One        X                                         X
A-Two                  X                        X   
B-One                             X                    X
C-One                                                  X

“名称”值和代码值的数量可以更改。它们不是恒定的。

目标是能够查看左侧的代码值列表 - 并轻松查看代码与哪些名称值相关联。

我认为这需要创建动态数据透视 sql,但我无法理解数据透视 sql,如果有任何帮助或指点,我将不胜感激。

【问题讨论】:

  • 早安塔莱,尝试按照这些步骤工作。展示您的成功之处,我们将添加缺少的步骤,以便您也了解未来案例的想法。 (1) 创建一个查询,返回表中所有不同名称的列表。 (2) 声明一个变量类型 NVARCHAR(MAX)。 (3) CONCAT 将第 1 步中的所有这些值从第 2 步中添加到您的变量中。(4) 使用特定的名称列表创建简单的数据透视查询 - 还不是动态查询...如果您完成了所有这些步骤,那么您只需要结合在一起,我遇到了消息长度的限制:-) 显示步骤 1-4
  • 非常感谢@Ronen Ariely!我很欣赏这不仅仅是一个现成的解决方案,因为你在教育我。我会按照你的 4 个步骤回帖。
  • 不客气。就像这句话说的“Give a man a fish and you feed him for a day. Teach a man to fish and you feed him for a lifetime”。不幸的是,大多数人都在争分夺秒而不是教书,发布最终查询比一步一步地跟踪线程要快得多,也简单得多。我的兴趣只在于帮助那些想自己学习如何做的人,而不是免费工作并在您无法从中学习的情况下提供最终查询:-)
  • 嗯...看来课程结束得太早了 ;-( 自从 Andrea 发表了最后一步。所以你可以标记他的答案并给他积分。他应该得到积分发布最终查询。话虽如此,我建议按照我给您的步骤继续工作,如果您愿意,我将解释最后一步:我们如何将步骤 1-4 中的所有信息合并到最终查询中:-)
  • 嗨@Ronen Ariely。我遵循了你的 4 个步骤。并且我了解了最后一步需要什么[而不是 Pivot 语句中的硬编码值,我必须根据所有不同的名称动态创建一个字符串]。我认为这部分对我来说会很困难,但如果你不介意帮忙的话,我决心理解整个事情。

标签: sql sql-server tsql pivot


【解决方案1】:

您可以使用动态枢轴:

create table dbo.test([Name] Varchar(32), Code Varchar(30)) 

insert into dbo.test values 
  ('A-1', 'A-One')
, ('A 2', 'A-Two')
, ('B 1-b', 'B-One')
, ('B', 'A-Two')
, ('C', 'A-One')
, ('C', 'B-One')
, ('C', 'C-One')

declare @cols nvarchar(max)=''  --holds all the values that will become column names 
declare @alias nvarchar(max)='' --holds values that will become column names and converts values to 'x'
declare @sql nvarchar(max)=''   --contains the TSQL dinamically generated 

select @cols = @cols + ', [' + [Name] + ']' 
from dbo.test 
group by [Name] 

select @alias = @alias + ', case when T.[' + [Name] + '] is not null then ''x'' else '''' end as [' + [Name] + ']'
from dbo.test 
group by [Name] 

set @cols = RIGHT(@cols, len(@cols)-2) 
set @sql = @sql + ' select  T.Code ' + @alias + ' from ('
set @sql = @sql + ' select piv.[Code], ' + @cols 
set @sql = @sql + ' from dbo.test ' 
set @sql = @sql + ' pivot (max([Name]) for [Name] in ('+@cols+') ) piv ' 
set @sql = @sql + ' ) T' 

--execute dynamic query
exec(@sql)

结果:

【讨论】:

  • 嗨@Andrea。您的代码适用于给定的数据。谢谢。但是,我正在使用的实际数据在名称字段中有连字符和空格。 sql 在名称字段中遇到空格或连字符时失败。代码字段中的空格和/或连字符不会导致错误。我该如何解决?
  • 您需要提供示例数据以便更好地理解并防止我们猜测,但乍一看和第一次猜测,Andre 解决方案中的问题似乎出在@alias 中。您需要对代码进行微小的修复。无论如何,如果我们一步一步地进行,那么您将学习如何在执行之前检查 cpde,您会立即注意到问题:-)。您可以使用PRINT @alias 了解问题所在,
  • 嗨!我已经编辑了原始帖子,所以现在样本中的数据应该会引发我得到的错误。谢谢!!
  • @Talay 只需在列名周围添加方括号。查看更新的答案。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2016-11-02
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多