多个表压缩为一行,具有不同的总计

时间:2013-08-07 14:41:44

标签: sql-server

我们有应用程序,它们在主机上运行,​​其上有软件。

应用程序可以在许多主机上运行。主机通常会在其上加载许多软件项。

我们使用Application表捕获此信息,并使用另外两个表来捕获关系,Application-Host,Host-Software。

但是,主机可能没有软件。 (它可能真的是空的,或者我们可能还没有信息,都需要突出显示。)

对于每个应用程序,我需要计算具有软件的主机。我无法找到办法。

假设一个应用程序有5个主机,其中四个连接到软件。一个关系表包含5个主机,另外4个主机的实例,但是4个通过第一个关系表间接连接。

我怎样才能得到正确答案,4?无论我做什么,我得到5,或所有主机上的软件项目总数。


这是我到目前为止所拥有的,包括调试代码。

select distinct
AH.APPLICATION_X_COMPONENT_NAME,
count(case when T.TECH_ITEM_REL_ITCM_CAT = 'Operating System' then 1 end) over      (partition by AH.APPLICATION_X_COMPONENT_NAME) as NoOfOpsys,
x.APPLICATION_X_COMPONENT_NAME,
x.HOST_COMPONENT_NAME,
x.NoHostsWithTIR
from dbo.CTO_TechnologyItemRelease as T

inner join dbo.CTOR_HOST_TECHITEMRELEASE as HT
on HT.TECH_ITEM_RELEASE_COMP_ID = T.TechnologyItemReleaseComponent

inner join dbo.CTOR_APPLICATIONX_HOST as AH
on AH.HOST_COMPONENT_ID = HT.HOST_COMPONENT_ID

inner join
(
select distinct
AH2.APPLICATION_X_COMPONENT_NAME,
AH2.HOST_COMPONENT_NAME,
count(case when HT2.HOST_COMPONENT_NAME is not null then 1 end) over (partition by AH2.APPLICATION_X_COMPONENT_NAME, HT2.HOST_COMPONENT_NAME) as NoHostsWithTIR
from dbo.CTOR_APPLICATIONX_HOST as AH2

inner join dbo.CTOR_HOST_TECHITEMRELEASE as HT2
on HT2.HOST_COMPONENT_NAME = AH2.HOST_COMPONENT_NAME
)
as x on x.APPLICATION_X_COMPONENT_NAME = AH.APPLICATION_X_COMPONENT_NAME

order by AH.APPLICATION_X_COMPONENT_NAME

数据:

App table
App_ID     App_Name
A0001      Application_1
A0002      Application_2
A0003      Application_3
A0004      Application_4

App-Host table
App_ID     App_Name              Host_ID  Host_Name
A0001      Application_1         H0001    Host_1
A0002      Application_2         H0001    Host_1
A0002      Application_2         H0002    Host_2
A0002      Application_2         H0003    Host_3
A0002      Application_2         H0004    Host_4
A0003      Application_3         H0005    Host_5
A0004      Application_4         H0002    Host_2
A0004      Application_4         H0006    Host_6

Host-TI table
Host_ID    Host_Name   TI_ID    TI_Name
H0001      Host_1      T0001    MS SQL Server 2005 SP1
H0001      Host_1      T0002    MS Windows Server 2008
H0002      Host_2      T0002    Red Hat Enterprise Linux 3
H0003      Host_3      T0002    MS Windows Server 2008
H0003      Host_3      T0003    Oracle Database Server 9i 9.2    
H0005     Host_5      T0001    MS SQL Server 2005 SP1
H0006      Host_6      T0004    Tivoli Storage Manager 5.2

TI table
TI_ID    TI_Name                          TI_Type
T0001    MS SQL Server 2005 SP1           Software Product
T0002    MS Windows Server 2008           Operating System
T0003    Red Hat Enterprise Linux 3       Operating System
T0003    Oracle Database Server 9i 9.2    Software Product
T0004    Tivoli Storage Manager 5.2       Software Product

所需的输出

App Name          Operating System count        Hosts with Tech Items
Application_1     1                             1       
Application_2     3                             3
Application_3     0                             1
Application_4     1                             2

关键的一行是Application_2,它有3个带有技术项目的主机。我只能在这个位置得到4,我的操作系统计数经常眨眼。

3 个答案:

答案 0 :(得分:1)

数据库设计看起来很严重,因此数据似乎不一致:

这些行似乎相互矛盾:

H0001      Host_1      T0002    MS Windows Server 2008
H0002      Host_2      T0002    Red Hat Enterprise Linux 3

这些:

T0003    Red Hat Enterprise Linux 3       Operating System
T0003    Oracle Database Server 9i 9.2    Software Product

我会假设数据无效,并且正确的数据是SQL Fiddle中的行。

根据这个假设,这段代码可以满足您的需求:

select a.app_ID, a.app_name, 
  (select Count(*) 
     from apphost ah
       inner join hostti ht on ah.host_id = ht.host_id
       inner join ti on ht.ti_id=ti.ti_id
   where ti_type = 'Operating System'
     and ah.app_id = a.app_id) as OSCount,
  (select Count(distinct ah.host_id) 
     from apphost ah
       inner join hostti ht on ah.host_id = ht.host_id
   where ah.app_id = a.app_id) as HostWithSoftwareCount
from App a 

答案 1 :(得分:0)

这样的事情:

select a.name, COUNT(*)
from application a
join application_host ah on (a.id = ah.application)
join host h on (h.id = ah.host)
where exists (select top 1 1 from host_software hs where hs.host = ah.host)
group by a.name

http://sqlfiddle.com/#!2/c4bbb/2

答案 2 :(得分:0)

我同意with @SWeko关于数据样本不一致的问题,以及我对这个问题的看法:

SELECT
  ap.App_Name,
  OperatingSystemCount = COUNT(ti.TI_ID),
  HostsWithTechItems   = COUNT(DISTINCT ah.Host_ID)
FROM
  App AS ap
  LEFT JOIN
    AppHost AS ah
    INNER JOIN HostTI AS ht ON ah.Host_ID = ht.Host_ID
    LEFT JOIN TI AS ti ON ht.TI_ID = ti.TI_ID AND ti.TI_Type = 'Operating System'
  ON ap.App_ID = ah.App_ID
GROUP BY
  ap.App_Name
;

此查询的SQL小提琴演示可在此处找到:http://sqlfiddle.com/#!3/677ae/3

请注意,在计算操作系统时,查询无法识别其中某些操作系统可能安装在同一主机上的事实:在这种情况下,每个实例都会被计算在内。如果您实际上打算使用操作系统计算主机,则需要通过将COUNT(ti.TI_ID)替换为类似

的内容来更改上述查询
COUNT(DISTINCT CASE WHEN ti.TI_ID IS NOT NULL THEN ah.Host_ID END)