如何在SQL中创建属性值表的视图

时间:2009-06-04 15:33:35

标签: sql sql-server

我在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'

4 个答案:

答案 0 :(得分:3)

恕我直言,这种代码(以及设计索引的麻烦)是你为“财产表”成语的灵活性支付的价格的一部分 - 你付钱,你选择了! - )< / p>

答案 1 :(得分: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 JOIN的原始查询将删除给定服务器的所有读数。不好。对于具有至少一个读数的任何服务器,此查询将为每个服务器返回一行。如果要返回所有服务器,无论是否有任何读数,请将INNER JOIN更改为LEFT JOIN。

  3. 除非您需要通过外键强制执行数据完整性,否则您不需要为您的统计名称使用单独的表。

答案 2 :(得分: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路连接切换为3路连接。是的,这是一个灵活性和简单性开始的情况。添加列是解决问题的一种更简洁的方法,因为数据库模式将精确匹配您收集的统计信息及其类型:但您需要保持它们同步。

(查询的nb语法未经测试,我假设CROSS JOIN以我期望的方式工作)

答案 3 :(得分:0)

这种设计大约是从关系到纯EAV(实体 - 属性 - 值)设计的一半。是的,他们对SQL数据库有一些可怕的方面我发现这个问题的最佳解决方案是使用立方体和/或数据透视表,而不是试图将这个圆形钉子敲入关系视图的方孔。

您可以使用的适合的事项:SSAS,Reporting Services数据透视报告,甚至是Excel数据透视表。