【问题标题】:SQL Syntax to Pivot multiple tables透视多个表的 SQL 语法
【发布时间】:2010-12-27 05:22:33
【问题描述】:

过去几天我一直在研究这个问题,并且正在兜圈子。

我的问题是基于我在这篇文章中接受的答案:stackoverflow question

感谢 Damir Sudarevic,我现在将我的数据从一个 400 列的表转移到一个更易于管理的数据库结构中。

我的数据库如下所示:

 CREATE TABLE JobFiles (
  JobID  UNIQUEIDENTIFIER PRIMARY KEY,
  MachineID UNIQUEIDENTIFIER REFERENCES Machines(MachineID),
  [Desc]  NVARCHAR(MAX),
  Name  NVARCHAR(255),
  JobOpen  BIT,
  [CreateDate]  DATETIME NOT NULL DEFAULT GETDATE(),
  [ModifyDate]  DATETIME NOT NULL DEFAULT GETDATE(),
  [CreatedByUser]  NVARCHAR(64)  DEFAULT '',
  [ModifiedByUser] NVARCHAR(64)  DEFAULT '')
GO 

 CREATE TABLE JobParamType (
  ParamTypeID UNIQUEIDENTIFIER PRIMARY KEY,
  Name  NVARCHAR(255),
  [Desc]  NVARCHAR(MAX),
  IsTrait  NVARCHAR)

GO
 CREATE TABLE JobParamGroup (
  ParamGroupID UNIQUEIDENTIFIER PRIMARY KEY,
  Name  NVARCHAR(255),
  [Desc]  NVARCHAR(MAX))

GO


 CREATE TABLE JobParams (
  ParamID  UNIQUEIDENTIFIER PRIMARY KEY,
  ParamTypeID UNIQUEIDENTIFIER REFERENCES JobParamType(ParamTypeID),
  ParamGroupID UNIQUEIDENTIFIER REFERENCES JobParamGroup(ParamGroupID),
  JobFileID UNIQUEIDENTIFIER REFERENCES JobFiles(JobID),
  IsEnabled BIT)

GO

 -- Text based property
 CREATE TABLE JobTrait (
  ParamID UNIQUEIDENTIFIER PRIMARY KEY REFERENCES JobParams(ParamID),
  Value  NVARCHAR(MAX) )
GO 

 -- Numeric based property 
 CREATE TABLE JobMeasurement (
  ParamID UNIQUEIDENTIFIER PRIMARY KEY REFERENCES JobParams(ParamID),
  Value FLOAT,
  Format NVARCHAR(20),
  Unit NVARCHAR(MAX) )
GO 

但是,对于我的应用程序的特定功能,我需要将每个 JobParamType.Name 行列为包含 JobMeasurement.Value 或 JobTrait.Value 作为每个 JobFiles.Name 的数据的列。

JobParamType.IsTrait 用于确定一个值是Measurement 还是Trait。

JobName  |  ParamName1      |  ParamName2      |  ParamName3       ... | ParamName400
"MyJob"     MesurementValue    TraitValue         MesurementValue  ...   TraitValue  
"TestJob"   MesurementValue    TraitValue         MesurementValue  ...   TraitValue  
"Job2"      MesurementValue    TraitValue         MesurementValue  ...   TraitValue  

etc

我一直在使用数据透视表,并通过查看示例并遵循它们设法从 JobParamType 表中获取列,但现在变得相当复杂,因为我的数据在多个表之间拆分并且它开始使我的头疼!!!

DECLARE @cols NVARCHAR(MAX)
SELECT  @cols = STUFF(( SELECT DISTINCT TOP 10 PERCENT
                                '],[' + tParams.Name
                        FROM    dbo.JobParamType  AS tParams
                        ORDER BY '],[' + tParams.Name
                        FOR XML PATH('')
                      ), 1, 2, '') + ']'
print @cols

我希望有人可以帮助我从多个表中进行数据透视和获取数据。

我希望这是有道理的,我期待您的帮助和讨论。

先谢谢你了。

【问题讨论】:

    标签: sql sql-server tsql pivot


    【解决方案1】:

    我将发布一些来自 this model 的示例——因为我已经有了它们。这两种模型非常相似,因此采用这种技术应该不会有太多麻烦。

    说到头疼,我发现最简单的方法就是一步一步走,以后再优化。

    第 1 步
    创建视图以展平模型; (see the model)

    CREATE VIEW dbo.vProperties AS 
    SELECT  m.MachineID AS [Machine ID]
    ,s.SetupID AS [Setup ID]
    ,p.PropertyID AS [Property ID]
    ,t.PropertyTypeID AS [Property Type ID]
    ,m.Name AS [Machine Name]
    ,s.Name AS [Setup Name]
    ,t.Name AS [Property Type Name]
    ,t.IsTrait AS [Is Trait]
    ,x.Value AS [Measurement Value]
    ,x.Unit AS [Unit]
    ,y.Value AS [Trait]
    FROM dbo.Machine AS m
    JOIN dbo.Setup AS s ON s.MachineID = m.MachineID
    JOIN dbo.Property AS p ON p.SetupID = s.SetupID
    JOIN dbo.PropertyType AS t ON t.PropertyTypeID = p.PropertyTypeID
    LEFT JOIN dbo.Measurement AS x ON x.PropertyID = p.PropertyID
    LEFT JOIN dbo.Trait AS y ON y.PropertyID = p.PropertyID
    

    第 2 步

    创建视图只生成[Setup Name], [Property Type Name], [Value];请注意,在这一列中,测量值和特征最终位于同一列中。你可能会使用JobName, ParameterTypeName, Value

    CREATE VIEW dbo.vSetupValues AS 
    SELECT  [Setup Name]
           ,[Property Type Name]
           ,COALESCE(cast([Measurement Value] AS varchar(50)), [Trait]) AS [Val]
    FROM dbo.vProperties
    

    第 3 步

    使用要排序的列创建属性(参数)列表

    DECLARE @Props TABLE (
    id int IDENTITY (1,1)
    ,PropName varchar(50)
    );
    
    INSERT INTO @Props  (PropName)
    SELECT DISTINCT [Name]
    FROM dbo.PropertyType
    

    第 4 步

    现在我将动态创建查询文本

    DECLARE @qw TABLE(
    id int IDENTITY (1,1)
    , txt nchar(500)
    )
    
    INSERT  INTO @qw (txt)
      SELECT  'SELECT' UNION
      SELECT  '[Setup Name]' ;
    
    INSERT  INTO @qw (txt)   
      SELECT  ',MAX(CASE [Property Type Name] WHEN ''' + PropName
      + ''' THEN Val ELSE NULL END) AS [' + PropName + ']'
      FROM  @Props
      ORDER BY id;
    
    INSERT  INTO @qw (txt)
     SELECT  'FROM dbo.vSetupValues' UNION
     SELECT  'GROUP BY [Setup Name]' UNION
     SELECT  'ORDER BY [Setup Name]';
    

    第 5 步

    这里是查询的文本,从这一点我可以把它打包成一个存储过程,另一个视图,或者一个变量来用作动态sql。

    SELECT txt FROM @qw
    

    返回

    SELECT                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                              
    [Setup Name]                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                        
    ,MAX(CASE [Property Type Name] WHEN 'Diameter LSL' THEN [Val] ELSE NULL END) AS [Diameter LSL]                                                                                                                                                                                                                                                                                                                                                                                                                      
    ,MAX(CASE [Property Type Name] WHEN 'Diameter USL' THEN [Val] ELSE NULL END) AS [Diameter USL]                                                                                                                                                                                                                                                                                                                                                                                                                      
    ,MAX(CASE [Property Type Name] WHEN 'Force LSL' THEN [Val] ELSE NULL END) AS [Force LSL]                                                                                                                                                                                                                                                                                                                                                                                                                            
    ,MAX(CASE [Property Type Name] WHEN 'Force USL' THEN [Val] ELSE NULL END) AS [Force USL]                                                                                                                                                                                                                                                                                                                                                                                                                            
    ,MAX(CASE [Property Type Name] WHEN 'Leak LSL' THEN [Val] ELSE NULL END) AS [Leak LSL]                                                                                                                                                                                                                                                                                                                                                                                                                              
    ,MAX(CASE [Property Type Name] WHEN 'Leak USL' THEN [Val] ELSE NULL END) AS [Leak USL]                                                                                                                                                                                                                                                                                                                                                                                                                              
    ,MAX(CASE [Property Type Name] WHEN 'Press Travel LSL' THEN [Val] ELSE NULL END) AS [Press Travel LSL]                                                                                                                                                                                                                                                                                                                                                                                                              
    ,MAX(CASE [Property Type Name] WHEN 'Press Travel USL' THEN [Val] ELSE NULL END) AS [Press Travel USL]                                                                                                                                                                                                                                                                                                                                                                                                              
    ,MAX(CASE [Property Type Name] WHEN 'Seal Height LSL' THEN [Val] ELSE NULL END) AS [Seal Height LSL]                                                                                                                                                                                                                                                                                                                                                                                                                
    ,MAX(CASE [Property Type Name] WHEN 'Seal Height USL' THEN [Val] ELSE NULL END) AS [Seal Height USL]                                                                                                                                                                                                                                                                                                                                                                                                                
    FROM dbo.vSetupValues                                                                                                                                                                                                                                                                                                                                                                                                                                                                                               
    GROUP BY [Setup Name]                                                                                                                                                                                                                                                                                                                                                                                                                                                                                               
    ORDER BY [Setup Name]                                      
    

    如果我运行这个:

    (来源:damirsystems.com


    更新:修复了第 4 步的错误,缺少 max() 并添加了结果示例。

    【讨论】:

    • 谢谢...非常感谢您的时间和努力。比我第一次要复杂一些,尽管今天这项任务将筛选您的示例并将其分解为多个步骤。
    • 达米尔,你是个天才,谢谢。这完美无缺。最后一个问题。我将如何像上面那样运行这个命令。第 5 步“SELECT txt FROM @qw”在表中显示命令(通过 SQL Management Studio),我必须将其复制并粘贴到新查询中。再次感谢您
    • 这个想法是将最终查询“打包”到视图、过程或变量中——这取决于您的参数列表可能更改的频率。如果这 400 个参数每年更改几次,请手动使用视图和构建更改。如果它们每天都在变化,请将其放入一个变量中并作为动态 sql 执行——也可以自动执行第 3 步和第 4 步。
    • 注意:在之前的评论中“参数多久更改一次”是指将新参数添加到列表中或重命名它们——而不是更改参数的值。
    • 参数可能会添加和删除新的参数,但可能不是每天。我想要实现的是将最终的选择查询放入一个变量中,以便我可以通过存储过程将其作为动态 sql 执行。我认为这将是最简单的一点,但我正在努力解决这一点。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2015-07-23
    • 2011-05-23
    • 2014-04-23
    • 1970-01-01
    • 1970-01-01
    • 2018-10-05
    • 1970-01-01
    相关资源
    最近更新 更多