2016-11-10 69 views
4

这是我第一次尝试使用PIVOT。 我正在使用Microsoft SQL Server。使用非数值数据枢轴

所以这里是我的问题,我一直在阅读Pivot,并且已经决定它对于将病人数据导出为格式化文件(即报告,可以打印出来等等)的项目非常有效。

VPatientPlusAllergyData是一个视图,显示这是一些数据的采样结果切出便于阅读

strPatientFullName strAllergy strAllergyMedication 
------------------------------------------------------------ 
Smith, John Henry Dogs  Pounces   
Smith, John Henry Dogs  Orange Juice   
Smith, John Henry Mustard  Ketchup   
Smith, John Henry Mustard  Sugar   

这是结果我想

strPatientFullName strAllergy1 strAllergy1Medications strAllergy2 strAllergy2Medications 
------------------------------------------------------------------------------------------------------ 
Smith, John Henry Dogs  Pounces, OrangeJuice  Mustard  Ketchup, Sugar 

在W3Schools上阅读后,观看Youtube视频,甚至阅读本网站上的一些文章,我想知道我正在尝试做什么是可能的

下面是一个代码片段,但我被困在我应该把什么IN声明,以及当我开始质疑PIVOT是否解决我的特定问题的可行性。

GO 
SELECT 
    strPatientFullName 
    ,strStreetAddress 
    ,strCity 
    ,strState 
    ,strZipcode 
    ,strPrimaryPhoneNumber 
    ,strSecondaryPhoneNumber 
    ,blnSmoker 
    ,decPackYears 
    ,blnHeadOfHousehold 
    ,dtmDateOfBirth 
    ,strSex 
    ,strAllergy 
    ,strAllergyMedication 
    ,strEmailAddress 
    ,strRecordCreator 

FROM (SELECT * FROM VPatientPlusAllergyData) PatientAllergyData 

PIVOT 
    (
     MAX(strAllergyMedication) 
     FOR strAllergy 
     IN() 
    ) 

GO 

希望有人更熟悉枢轴会告诉我什么我失踪或启发我一个更有效的解决方案。

感谢您的帮助

******编辑:我已经决定了,虽然我很想把这种操作在服务器端,我的具体应用,它只是简单的创建大量的视图然后在客户端执行SELECT查询并将它们连接在一起,然后执行“EXPORT PROCESSING”屏幕。 我感谢所有的帮助,也许在一天我会写一个脚本,并让它执行服务器端,但目前这项工作足够好****** ******

+0

编辑:其实,没关系,我没有正确地阅读你的问题。看来,你的问题需要混合旋转和填充。 – ZLK

+0

假设过敏的值可以是n个,那么您需要为此使用'DYNAMIC SQL'。这是一个很好的教程。 http://sqlhints.com/2014/03/18/dynamic-pivot-in-sql-server/ – scsimon

回答

1

下面是一个如何可以做类似的例子这与一个STUFF语句,条件聚合和动态SQL。

DECLARE @SQL NVARCHAR(MAX) = ''; 
SELECT @SQL += ' 
    , MAX(CASE WHEN RN = ' + RN + ' THEN strAllergy END) strAllergy' + RN + ' 
    , MAX(CASE WHEN RN = ' + RN + ' THEN strAllergyMedications END) strAllergyMedications' + RN 
FROM (
    SELECT CAST(ROW_NUMBER() OVER (PARTITION BY strPatientFullName, strAllergy ORDER BY (SELECT NULL)) AS VARCHAR(5)) RN 
    FROM VPatientPlusAllergyData) T 
GROUP BY RN; 

SELECT @SQL = 'SELECT strPatientFullName' + @SQL + ' 
FROM (
    SELECT strPatientFullname 
     , strAllergy 
     , STUFF((SELECT '', '' + strAllergyMedication FROM VPatientPlusAllergyData WHERE strPatientFullName = T.strPatientFullName AND strAllergy = T.strAllergy FOR XML PATH ('''')), 1, 2, '''') strAllergyMedications 
     , ROW_NUMBER() OVER (ORDER BY (SELECT NULL)) RN 
    FROM VPatientPlusAllergyData T 
    GROUP BY strPatientFullname, strAllergy) T 
GROUP BY strPatientFullname;'; 

PRINT @SQL; 
EXEC(@SQL); 

由于scsimon提到的意见,动态SQL可能是必要的,如果可以有任意数量的过敏。东西声明是将逗号分隔值转换为单个列的一种方法。和条件聚合工作在相同的方式,枢轴会正常工作,但要容易得多(IMO)编写和理解比正常PIVOT声明。

+0

当我看到你的答案时,我几乎要按下save。无论如何,我都加入了我的工作来分解这些部分,这样OP就可以动态地理解你正在做什么,+1为了一个好的解决方案而欢呼。 – Matt

+0

RN代表RowNumber吗?或随机数? – user3119737

+0

@ user3119737 RowNumber。它只是ROW_NUMBER()窗口函数的列别名。 'CAST(ROW_NUMBER()OVER(PARTITION BY strPatientFullName,strAllergy ORDER BY(SELECT NULL))AS VARCHAR(5))AS [RN]'在功能上是相同的,如果有意义的话。 – ZLK

2

所以去你想你实际上是在寻找需要下面的技巧是什么:

  • 对于你需要strAllergyMedications到串联行来分隔字符串
  • 随后的情况下让你的行成列,你需要PIVOT,而是因为你是旋转2列,你将不得不PIVOT两次或使用条件聚合

拉动它的主要技巧是通过连接并为过敏提出一个行号来准备表。以下是使用公共表格表达式[CTE]和STUFF()以及子选择XML创建分隔字符串并创建行号的示例。

DECLARE @VPatientPlusAllergyData AS TABLE (strPatientFullName VARCHAR(100), strAllergy VARCHAR(50), strAllergyMedication VARCHAR(100)) 
INSERT INTO @VPatientPlusAllergyData VALUES 
('Smith, John Henry','Dogs','Pounces') 
,('Smith, John Henry','Dogs','Orange Juice') 
,('Smith, John Henry','Mustard','Ketchup') 
,('Smith, John Henry','Mustard','Sugar') 

;WITH cte AS (
    SELECT DISTINCT 
     v1.strPatientFullName 
     ,v1.strAllergy 
     ,strAllergyMedications = STUFF(
      (SELECT ', ' + v2.strAllergyMedication 
      FROM 
       @VPatientPlusAllergyData v2 
      WHERE 
      v1.strPatientFullName = v2.strPatientFullName 
      AND v1.strAllergy = v2.strAllergy 
      FOR XML PATH('')) 
      ,1,2,'') 
     ,AllergyRowNum = DENSE_RANK() OVER (PARTITION BY v1.strPatientFullName ORDER BY v1.strAllergy) 
    FROM 
     @VPatientPlusAllergyData v1 
) 

SELECT 
    strPatientFullName 
    ,strAllergy1 = MAX(CASE WHEN AllergyRowNum = 1 THEN strAllergy END) 
    ,strAllergy1Medications = MAX(CASE WHEN AllergyRowNum = 1 THEN strAllergyMedications END) 
    ,strAllergy2 = MAX(CASE WHEN AllergyRowNum = 2 THEN strAllergy END) 
    ,strAllergy2Medications = MAX(CASE WHEN AllergyRowNum = 2 THEN strAllergyMedications END) 
FROM 
    cte 
GROUP BY 
    strPatientFullName 

而当我准备和发布这@ZLK写了一个很好的方法来动态地做到这一点。

+0

你说过我必须两次枢轴?你可以给我一个例子,用你的上面的例子吗?将不胜感激。 – user3119737

+0

那么,如果您使用PIVOT,则一次只能旋转1列。所以现实是你必须先发生PIVOT然后有条件的汇总,否则你必须先将一列纵列,然后将另一列纵列,然后再选择DISTINCT。 PIVOT仅用于1列和1个聚合。我可能会回来,但现在我会记得1列的规则是PIVOT 1 PIVOT聚合。但是条件聚合没有这个限制。基本上任何时候你想要做一个复杂的枢轴只是使用条件聚合 – Matt