[英]Complex SQL Pivot query
快速背景知识使我的问题变得有意义:系统以问卷的形式从用户那里收集数据。 用户属于组织,组织属于部门,并且各个部门的问题/计算方式(在调查表中可以找到)不同。 (问题由用户回答;计算由系统计算)。
存在以下表格:
部门 ( 部门 ID,名称)
组织 (组织ID,名称,部门ID)
年 (YearID,姓名)
问题 (QuestionID,DisplayText,CommonName,SectorID)
答案 ( 答案 ID,答案,组织ID,年份ID,问题ID)
计算 (CalculationID,DisplayText,CommonName,SectorID)
CalculationResults (CalculationResultID,Result,OrganizationID,YearID,CalculationID)
我需要通过以下方式显示数据:
(对我而言)使问题特别复杂的是,问题在它们所属的不同部门之间以不同的方式(向用户显示),但是其中一些仍然是常见问题。 例如,“制造销售”将与“销售(制造)”相同。 我需要使用CommonName
字段来确定通用性。
我设法使用SQL Pivot接近我想要的-SQL Fiddle (如果运行SQL,您会注意到null和“ commonality”问题)。 但是,我的尝试中缺少一些东西:
通用性和列名-我需要将列名设置为CommonName
字段,而不是QuestionID
字段。
我只从“ 答案”表中进行选择-我还需要从结构相同的CalculationResults表中进行选择。
编辑 :与SQL Fiddle数据所需的结果是: (两个带有橙色角的块需要一直向左移动,因此问题总共有3列-3个唯一的
CommonName
值。接下来的3列是3个唯一的CommonName
值,用于计算我希望我有道理,如果没有让我知道。)
Edit2 :另一个有趣的编辑。 我确实考虑过重新设计数据库,但是在当前阶段这不是一个选择-在此旧系统上风险太大。 以防万一有人看到设计并以为如此。 我希望有一个Pivot形式的解决方案。
基本上,我们希望得到Grouped By
SectorID
和Name
Grouped By
的QuestionID
的顺序。
您可以使用PARTITION BY
进行以下操作:
ROW_NUMBER() OVER(PARTITION BY q.SectorID, y.Name ORDER BY a.QuestionID)
这应该做到这一点:
DECLARE @cols AS NVARCHAR(MAX)
, @query AS NVARCHAR(MAX);
SELECT @cols = STUFF(
(SELECT DISTINCT
','+QUOTENAME(CAST(ROW_NUMBER() OVER(PARTITION BY q.SectorID
, y.Name ORDER BY a.QuestionID) AS VARCHAR(10)))
FROM Answers a
LEFT JOIN Years y ON a.YearID = y.YearID
LEFT JOIN Organisations o ON a.OrganisationID = o.OrganisationID
LEFT JOIN Questions q ON a.QuestionID = q.QuestionID
FOR XML PATH(''), TYPE).value
('.', 'NVARCHAR(MAX)'), 1, 1, '');
SET @query = '
SELECT Organisation, Year, '+@cols+' from
(
SELECT QuestionID = ROW_NUMBER() OVER(PARTITION BY q.SectorID
, y.Name ORDER BY a.QuestionID)
, o.Name AS Organisation
, y.Name AS Year
, a.Answer
FROM Answers a
LEFT JOIN Years y ON a.YearID = y.YearID
LEFT JOIN Organisations o ON a.OrganisationID = o.OrganisationID
LEFT JOIN Questions q ON a.QuestionID = q.QuestionID
) src
pivot
(
max(Answer)
for QuestionID in ('+@cols+')
) piv
order by Organisation, Year
';
PRINT(@query);
EXECUTE (@query);
结果:
有时可以使用[Aggregate](CASE EXPRESSION)
代替PIVOT
获得相同的数据。 有时更快。
对于您的问题,可以将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
'
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.