2016-11-10 102 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