2009-06-04 110 views
1

我有一個SQL表中有四列的表。其中兩個是存儲我們的服務器的性能指標的屬性和值列。我們不斷提出新的性能指標,我們不想重新設計我們的模式,所以我們這樣設計表格。如何在SQL中創建關閉屬性值表的視圖

問題是,當我創建一個視圖來查看錶格,就好像它的正常化一樣,我得到一個查詢,只是尖叫「哦,我的上帝這是廢話代碼」,因爲它涉及一個表連接了12次。這是我用於查看的查詢。

基本上,這感覺就像我做的事情真的不對,但我找不出解決問題的更好方法。

SELECT 
    astats.AQTORStatsID, 
    astats.ServerName, 
    astats.Remarks, 
    astats.StatsBeginDateTime, 
    astats.StatsEndDateTime, 
    asi1.AQTORStatValue as 'QtCPU_Average', 
    asi2.AQTORStatValue as 'QtCPU_TopQuintile', 
    asi3.AQTORStatValue as 'QtCPU_TopOnePercent', 
    asi4.AQTORStatValue as 'QtCl_Average', 
    asi5.AQTORStatValue as 'QtCl_TopQuintile', 
    asi6.AQTORStatValue as 'QtCl_TopOnePercent', 
    asi7.AQTORStatValue as 'UpdPrcStd_Average', 
    asi8.AQTORStatValue as 'UpdPrcStd_TopQuintile', 
    asi9.AQTORStatValue as 'UpdPrcStd_TopOnePercent', 
    asi10.AQTORStatValue as 'RcRsUPr_Average', 
    asi11.AQTORStatValue as 'RcRsUPr_TopQuintile', 
    asi12.AQTORStatValue as 'RcRsUPr_TopOnePercent' 
FROM 
    tb_rAQTORStatsItem asi1 
    INNER JOIN tb_rAQTORStatsItem asi2 ON asi1.AQTORStatsID = asi2.AQTORStatsID 
    INNER JOIN tb_rAQTORStatsItem asi3 ON asi2.AQTORStatsID = asi3.AQTORStatsID 
    INNER JOIN tb_rAQTORStatsItem asi4 ON asi3.AQTORStatsID = asi4.AQTORStatsID 
    INNER JOIN tb_rAQTORStatsItem asi5 ON asi4.AQTORStatsID = asi5.AQTORStatsID 
    INNER JOIN tb_rAQTORStatsItem asi6 ON asi5.AQTORStatsID = asi6.AQTORStatsID 
    INNER JOIN tb_rAQTORStatsItem asi7 ON asi6.AQTORStatsID = asi7.AQTORStatsID 
    INNER JOIN tb_rAQTORStatsItem asi8 ON asi7.AQTORStatsID = asi8.AQTORStatsID 
    INNER JOIN tb_rAQTORStatsItem asi9 ON asi8.AQTORStatsID = asi9.AQTORStatsID 
    INNER JOIN tb_rAQTORStatsItem asi10 ON asi9.AQTORStatsID = asi10.AQTORStatsID 
    INNER JOIN tb_rAQTORStatsItem asi11 ON asi10.AQTORStatsID = asi11.AQTORStatsID 
    INNER JOIN tb_rAQTORStatsItem asi12 ON asi11.AQTORStatsID = asi12.AQTORStatsID 
    INNER JOIN tb_dAQTORStats astats on asi12.AQTORStatsID = astats.AQTORStatsID 
WHERE 
    asi1.AQTORStatName = 'QtCPU_Average' 
AND asi2.AQTORStatName = 'QtCPU_TopQuintile' 
AND asi3.AQTORStatName = 'QtCPU_TopOnePercent' 
AND asi4.AQTORStatName = 'QtCl_Average' 
AND asi5.AQTORStatName = 'QtCl_TopQuintile' 
AND asi6.AQTORStatName = 'QtCl_TopOnePercent' 
AND asi7.AQTORStatName = 'UpdPrcStd_Average' 
AND asi8.AQTORStatName = 'UpdPrcStd_TopQuintile' 
AND asi9.AQTORStatName = 'UpdPrcStd_TopOnePercent' 
AND asi10.AQTORStatName = 'RcRsUPr_Average' 
AND asi11.AQTORStatName = 'RcRsUPr_TopQuintile' 
AND asi12.AQTORStatName = 'RcRsUPr_TopOnePercent' 

回答

2

這裏是你如何做到這一點:

SELECT 
    astats.AQTORStatsID 
, astats.ServerName 
, astats.Remarks 
, astats.StatsBeginDateTime 
, astats.StatsEndDateTime 

, QtCPU_Average   = max(case when asi.AQTORStatName = 'QtCPU_Average'   then asi.AQTORStatValue end) 
, QtCPU_TopQuintile  = max(case when asi.AQTORStatName = 'QtCPU_TopQuintile'  then asi.AQTORStatValue end) 
, QtCPU_TopOnePercent  = max(case when asi.AQTORStatName = 'QtCPU_TopOnePercent'  then asi.AQTORStatValue end) 
, QtCl_Average   = max(case when asi.AQTORStatName = 'QtCl_Average'   then asi.AQTORStatValue end) 
, QtCl_TopQuintile  = max(case when asi.AQTORStatName = 'QtCl_TopQuintile'  then asi.AQTORStatValue end) 
, QtCl_TopOnePercent  = max(case when asi.AQTORStatName = 'QtCl_TopOnePercent'  then asi.AQTORStatValue end) 
, UpdPrcStd_Average  = max(case when asi.AQTORStatName = 'UpdPrcStd_Average'  then asi.AQTORStatValue end) 
, UpdPrcStd_TopQuintile = max(case when asi.AQTORStatName = 'UpdPrcStd_TopQuintile' then asi.AQTORStatValue end) 
, UpdPrcStd_TopOnePercent = max(case when asi.AQTORStatName = 'UpdPrcStd_TopOnePercent' then asi.AQTORStatValue end) 
, RcRsUPr_Average   = max(case when asi.AQTORStatName = 'RcRsUPr_Average'   then asi.AQTORStatValue end) 
, RcRsUPr_TopQuintile  = max(case when asi.AQTORStatName = 'RcRsUPr_TopQuintile'  then asi.AQTORStatValue end) 
, RcRsUPr_TopOnePercent = max(case when asi.AQTORStatName = 'RcRsUPr_TopOnePercent' then asi.AQTORStatValue end) 

from tb_dAQTORStats astats 
join tb_rAQTORStatsItem asi on asi.AQTORStatsID = astats.AQTORStatsID 

group by 
    astats.AQTORStatsID 
, astats.ServerName 
, astats.Remarks 
, astats.StatsBeginDateTime 
, astats.StatsEndDateTime 

注:

  1. 具有列模式或矩形編輯功能的優秀文本編輯器確實有助於這種事情。想起UltraEdit或Emacs。大約一分鐘後,我在UltraEdit中創建了上述內容。

  2. 如果缺少一種類型的閱讀,您的INNER JOINs原始查詢將丟棄給定服務器的所有讀數。不好。對於至少具有一個讀數的任何服務器,此查詢將爲每臺服務器返回一行。如果您想要返回所有服務器,無論是否有讀數,請將INNER JOIN更改爲LEFT JOIN。

  3. 除非需要通過外鍵強制執行數據完整性,否則不需要爲您的統計名稱使用單獨的表。

+0

我們使用父表來存儲有關我們在生成統計信息的時間段內所做的操作的信息。也就是說,它對我們正在使用的性能增強技術進行了評論,並提供了與收集的所有統計數據相關的其他信息。 – 2009-06-09 15:07:16

3

恕我直言,這種代碼(以及煩惱設計指數)是你所支付的「屬性表」成語的靈活性爲代價的一部分 - 你付出你的錢,你需要你的選擇! - )

0

有包含所有可能的統計名字(我想你應該有,無論如何,從tb_rAQTORStatsItem的FKEY約束到它)

然後你就可以有類似的表:

SELECT astats.QTORStatsID, astats.ServerName, astats.Remarks, 
     astats.StatsBeginDateTime, astats.StatsEndDateTime, 
     max(case item.AQTORStatName when 'QtCPU_Average' then AQTORStatValue end) as QtCPU_Average, 
     max(case item.AQTORStatName when 'QtCPU_TopQuintile' then AQTORStatValue end) as QtCPU_TopQuintile, 
     /* repeat for each statistic... */ 
FROM tb_dAQTORStats astats 
    CROSS JOIN tb_rAQTORStatNames statnames 
    LEFT JOIN tb_rAQTORStatsItem item 
      ON item.AQTORStatName = statnames.AQTORStatName 
      AND item.AQTORStatsID = astats.AQTORStatsID 
GROUP BY astats.QTORStatsID, astats.ServerName, astats.Remarks, 
     astats.StatsBeginDateTime, astats.StatsEndDateTime 

雖然這仍然非常醜陋,但至少可以將N路連接切換爲三路連接。是的,這是一個靈活性和簡單性的例子。添加列是一種解決問題的方式,因爲數據庫模式將精確地匹配您收集的統計數據和它們的類型:但您需要保持同步。

(查詢NB語法沒有測試,我假設CROSS JOIN的工作在我所期望的方式)

0

這種設計大約是從關係到純EAV(實體 - 屬性 - 值)設計的一半。是的,他們有一些SQL數據庫的醜陋方面我發現這個問題的最佳解決方案是使用立方體和/或數據透視表,而不是試圖將這個圓柱釘入關係視圖的方孔。

您可以使用的功能:SSAS,Reporting Services數據透視報告,甚至Excel透視表。