2009-06-04 114 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透视表。