复杂的SQL Pivot查询

时间:2016-03-17 16:11:48

标签: sql tsql sql-server-2012 pivot

快速背景,以便我的问题有意义:系统以问卷形式从用户收集数据。用户属于组织,组织属于部门,问题/计算(如调查问卷中所示)在各部门之间有所不同。 (问题由用户回答;计算由系统计算)。

存在以下表格:

部门(SectorID,名称)
组织(OrganisationID,Name,SectorID)
(年份ID,姓名)

问题(QuestionID,DisplayText,CommonName,SectorID)
答案(AnswerID,答案,OrganisationID,YearID,QuestionID)

计算(CalculationID,DisplayText,CommonName,SectorID)
CalculationResults (CalculationResultID,Result,OrganisationID,YearID,CalculationID)

我需要以下列方式显示数据:

view

使这个特别复杂的事情(对我而言)是问题在他们所属的不同部门以不同方式显示(对用户),但其中一些问题仍然是常见问题。例如。 "制造销售"与#34;销售(制造)"相同。我需要使用CommonName字段来确定共性。

我设法使用SQL Pivot接近我想要的东西 - SQL Fiddle(如果你运行SQL,你会注意到空值和"共性"问题)。但是我的尝试中缺少一些东西:

  1. 通用名和列名 - 我需要将列名称设为CommonName字段,而不是QuestionID字段。

  2. 我只选择了答案表 - 我还需要从结构相同的 CalculationResults 表中进行选择。

  3. 编辑:SQL小提琴数据所需的结果是: enter image description here (具有橙色角的两个块需要一直向左移动,因此问题总共有3列 - 3个唯一CommonName值。接下来的3列是3个唯一的计算的CommonName值。如果不让我知道,我希望我有道理。)

    Edit2 :另一个编辑只是为了好玩。我一直在考虑重新设计数据库,但在现阶段它不是一个选项 - 在这个遗留系统上风险太大。如果有人看到设计并认为。我希望以Pivot的形式提供解决方案。

2 个答案:

答案 0 :(得分:1)

基本上我们希望获得print new mmsi d ts lat lon 0 0 77 1458213600 46.367553 48.01107 1 0 77 1458214200 46.367553 48.01107 2 0 77 1458213000 46.367553 48.01107 3 0 77 1458215400 46.367553 48.01107 4 0 77 1458217200 46.367553 48.01107 print old mmsi d lat lon ts 0 0 77 48.01107 122.179 1458213600 1 0 77 48.01107 122.179 1458214200 2 0 77 48.01107 122.179 1458214800 3 0 77 48.01107 122.179 1458217200 4 0 77 48.01107 122.179 1458220800 #added custom suffixes print pd.merge(new,old,on=['mmsi','d','ts'], how='inner', suffixes=('_new','_old')) mmsi d ts lat_new lon_new lat_old lon_old 0 0 77 1458213600 46.367553 48.01107 48.01107 122.179 1 0 77 1458214200 46.367553 48.01107 48.01107 122.179 2 0 77 1458217200 46.367553 48.01107 48.01107 122.179 QuestionID Grouped BySectorID的顺序。

您可以使用Name执行此操作,如下所示:

PARTITION BY

这应该这样做:

ROW_NUMBER() OVER(PARTITION BY q.SectorID, y.Name ORDER BY a.QuestionID)

结果:

enter image description here

答案 1 :(得分:1)

有时候您可以使用PIVOT代替[Aggregate](CASE EXPRESSION)来获取相同的数据。有时候它会更快。

对于您的问题,您可以将OUTER APPLY与动态MAX(CASE)

一起使用
DECLARE @Questions NVARCHAR(MAX),
        @Calculations NVARCHAR(MAX),
        @Sql NVARCHAR(MAX)

SELECT  @Questions = COALESCE(@Questions + ', ', '') 
            + 'MAX(CASE WHEN q.CommonName = ''' + CommonName + ''' THEN a.Answer END) AS ' + QUOTENAME(CommonName)
FROM    Questions 
GROUP BY CommonName

SELECT  @Calculations = COALESCE(@Calculations + ', ', '') 
            + 'MAX(CASE WHEN c.CommonName = ''' + CommonName + ''' THEN cr.Result END) AS ' + QUOTENAME(CommonName)
FROM    Calculations  
GROUP BY CommonName

SET     @Sql = N'
        SELECT 
            o.Name As [Organisation],
            y.Name As [Year],
            q.*,
            c.*
        FROM 
            Organisations o
            CROSS JOIN Years y
            OUTER APPLY (
                SELECT ' + @Questions + ' 
                FROM    Answers a 
                        JOIN Questions q ON a.QuestionID = q.QuestionID
                WHERE   a.OrganisationID = o.OrganisationID 
                        AND a.YearID = y.YearID
            ) q
            OUTER APPLY (
                SELECT ' + @Calculations + ' 
                FROM    CalculationResults cr 
                        JOIN Calculations c ON cr.CalculationID = c.CalculationID
                WHERE   cr.OrganisationID = o.OrganisationID 
                        AND cr.YearID = y.YearID
            ) c
'

SQL FIDDLE DEMO