SQL Server - 如果字段已经转动,如何通过另一个字段再次转动? DB设计是否正确?

时间:2017-12-29 09:49:49

标签: sql sql-server

我有像

这样的原始数据

Title    Question  Answer  AnswerRemark
----------------------------------------
ACCCode1    Q1       Y        NULL
ACCCode1    Q2       N        6
ACCCode1    Q3       Y        Workout

正如您所看到的,“AnswerRemark”字段是“答案”的自由文本,某些答案不需要备注。

我可以简单地转动问题并回答如下:

Title         Q1   Q2   Q3
AccessCode1   Y    N    Y

我想要的结果将是

Title         Q1   R1   Q2   R2   Q3   R3
AccessCode1   Y   NULL  N    6     Y   Workout 

这可能吗?我无法弄清楚如何实现这一点,因为它有许多组合,所以答案并不是一个好主意。

有什么建议吗?

3 个答案:

答案 0 :(得分:2)

使用条件聚合:

SELECT Title,
    MAX(CASE WHEN Question='Q1' THEN Answer  END) as Q1  ,
    MAX(CASE WHEN Question='Q1' THEN AnswerRemark  END) as R1 ,
    MAX(CASE WHEN Question='Q2' THEN Answer  END) as Q2  ,
    MAX(CASE WHEN Question='Q2' THEN AnswerRemark  END) as R2 ,
    MAX(CASE WHEN Question='Q3' THEN Answer  END) as Q3  ,
    MAX(CASE WHEN Question='Q3' THEN AnswerRemark  END) as R3 
FROM [tablename]
GROUP BY Title

答案 1 :(得分:0)

使用Pivot我们得到结果

 ;With cte(Title, Question,Answer,AnswerRemark)
AS
(
SELECT 'ACCCode1','Q1','Y',NULL      UNION ALL
SELECT 'ACCCode1','Q2','N','6'       UNION ALL
SELECT 'ACCCode1','Q3','Y','Workout' UNION ALL
SELECT 'ACCCode1','Q2','N','7'       UNION ALL
SELECT 'ACCCode1','Q1','Y',NULL      UNION ALL
SELECT 'ACCCode1','Q3','N','9'       UNION ALL
SELECT 'ACCCode1','Q1','N','4'       UNION ALL
SELECT 'ACCCode1','Q2','N','Workout' UNION ALL
SELECT 'ACCCode1','Q4','N','2'       UNION ALL
SELECT 'ACCCode1','Q3','Y','Workout' UNION ALL
SELECT 'ACCCode1','Q1','N','1'       UNION ALL
SELECT 'ACCCode1','Q4','Y',NULL
)

SELECT *,'Remark'+CAST(ROW_NUMBER()OVER(ORDER BY (SELECT 1))AS varchar(10)) AS Question2 
, ROW_NUMBER()OVER(PArtition  by Question Order by Question ) AS Seq  
INTO #t FROM cte

使用动态Sql,其中列不是静态的

DECLARE @DyColumn1 Nvarchar(max),
        @DyColumn2 Nvarchar(max),
        @Sql Nvarchar(max),
        @MAxDyColumn1 Nvarchar(max),
        @MAxDyColumn2 Nvarchar(max),
        @CombineColumn Nvarchar(max)


SELECT @DyColumn1=STUFF((SELECT DISTINCT ', '+QUOTENAME(Question) FROM #t FOR XML PATH ('')),1,1,'')
SELECT @DyColumn2=STUFF((SELECT ', '+QUOTENAME(Question2) FROM #t FOR XML PATH ('')),1,1,'')

SELECT @MAxDyColumn1=STUFF((SELECT DISTINCT ', '+'MAX('+QUOTENAME(Question)+') AS '+QUOTENAME(Question) FROM #t FOR XML PATH ('')),1,1,'')
SELECT @MAxDyColumn2=STUFF((SELECT ', '+'MAX('+QUOTENAME(Question2)+') AS '+QUOTENAME(Question2) FROM #t FOR XML PATH ('')),1,1,'')

SELECT @CombineColumn=STUFF((SELECT DISTINCT ', '+QUOTENAME(Question)+','+QUOTENAME(Question2) FROM #t FOR XML PATH ('')),1,1,'')



SET @Sql='SELECT Title,'+@CombineColumn+' From
(
SELECT Title,'+@MAxDyColumn1+','+@MAxDyColumn2+' FRom
(
SELECT * FROM #t
)AS SRC
    PIVOT
    (
    MAX(Answer) FOR Question IN('+@DyColumn1+')
    ) AS Pvt1

    PIVOT
    (
    MAX(AnswerRemark) FOR Question2 IN('+@DyColumn2+')
    ) AS Pvt2
    GROUP BY Title
    )dt
'
PRINT @Sql
EXEC(@Sql)

结果

Title   Q1  Remark1 Q1  Remark2 Q1  Remark3 Q1  Remark4 Q2  Remark5 Q2  Remark6 Q2  Remark7 Q3  Remark8 Q3  Remark9 Q3  Remark10    Q4  Remark11    Q4  Remark12
ACCCode1    Y   NULL    Y   1   Y   4   Y   NULL    N   6   N   Workout N   7   Y   Workout Y   Workout Y   9   Y   NULL    Y   2

答案 2 :(得分:0)

我不知道您的数据有多大,或者可能有多少问题。在表示层完成的更通用的Q& A结构会好得多,但是对于您的特定请求,更正确的设计将是3NF表。这将允许您创建高度优化的主键,并按问题类型ID创建二级索引。现在所有的密钥都是ID,搜索和匹配的速度比字符串快得多:

Account Codes
AccID - AccName - columns for other data related to accounts

存储您拥有的每个帐户。

Questions
QuestionID - QuestionName

可能的问题列表,每个问题都有一行,Q1,Q2等。您可以在此处添加问题类别以利用您拥有的任何共性,例如:如果您对同一组问题进行了不同的调查,您可以将它们放在一个类别中,然后轻松查询下面的内容。

Results
AccId, QuestionID, Result, Result Remark

每个问题都包含一行。

查询结果仍然使用pivot,但现在您可以从变量或动态SQL语法中选择要使用的列列表,这意味着您可以更好地控制它,并且查询本身应该更好。

话虽如此,如果您对数据有任何了解,可以使用它来制作静态查询,然后可以将其编入索引。此查询的示例如下:SQL Server 2005 Pivot on Unknown Number of Columns。然后,您可以根据需要使用AS语法设置列名称,遗憾的是,这会再次需要动态sql(Change column name while using PIVOT SQL Server 2008)。

顺便说一句,你要做的是专门处理非规范化数据,这是nosql的优点,SQL Server为你提供了很大帮助,但你必须对你的数据有一些结构。

如果你不是为调查猴子工作并处理数以百万计的变种,我会认真考虑你是否可以只针对你得到的每一轮问题制作一个表格,然后简单地对其进行非规范化并添加一个明确的每个问题的列,然后将整个逻辑设为select * from surveyxyztable where accountid = abc