我目前正在尝试制定查询以确定是否在所述主机上安装了某些软件应用程序。我们在数据库中的表是以包含主机名和软件的列的方式设置的,例如,可能有10个主机A的记录,展示了在其上找到的10个单独的软件。恩。以下
ID Host SW
--------------------------
1 Host A SW A
1 Host A SW B
1 Host A SW C
2 Host B SW B
2 Host B SW C
3 Host C SW F
我想要找到的是安装了软件A(标记Y / N)和安装了软件B(标记Y / N)的所有主机,并以某种方式格式化结果(使用上面的示例)会回来......
Expected Results
Host SWA_Installed SWB_Installed
----------------------------------------------
Host A Y Y
Host B N Y
Host C N N
我在下面的查询是我到目前为止(注意实际的DB代码,那些是实际的SW名称)...
SELECT DISTINCT
HOST.a_display_label AS HOST,
CASE
WHEN
sof.a_display_label = 'HPS' THEN 'Y'
ELSE 'N'
END AS HPS_INSTALLED,
CASE
WHEN
sof.a_display_label = 'PowerToken' THEN 'Y'
ELSE 'N'
END AS PT_INSTALLED
FROM vcms.node_1 HOST
JOIN vcms.installed_software_1 sof
ON LOWER (sof.a_root_container) = LOWER (HOST.cmdb_id)
问题在于即使它正在抓取DISTINCT结果,它仍然会为主机返回多条记录,因为它上面安装了每个软件的多个主机记录。最终结果如下:
Query Results
Host SWA_Installed SWB_Installed
----------------------------------------------
Host A Y N
Host A N Y
Host A N N
Host B N N
Host B N Y
Host C N N
我想知道返回“预期结果”数据需要哪些其他信息。提前谢谢。
答案 0 :(得分:2)
只需使用条件聚合:
select h.a_display_label as host,
max(case when s.a_display_label = 'HPS' then 'Y' else 'N'
end) as hps_installed,
max(case when s.a_display_label = 'PowerToken' then 'Y' else 'N'
end) as pt_installed
from vcms.node_1 h join
vcms.installed_software_1 s
on lower(s.a_root_container) = lower(h.cmdb_id)
group by h.a_display_label;
注意:这取决于'Y'
> 'N'
,因此逻辑不适用于min()
而不是max()
。我通常只使用“1”表示“是”而“0”表示否,而不是字符。
我还应该评论我发现SELECT DISTINCT
聚合函数是一个非常笨拙的构造。对于聚合查询,您应该考虑GROUP BY
而不是SELECT DISTINCT
。
答案 1 :(得分:1)
您需要在“主机”列上进行聚合。在max
表达式上使用min
或case
,因为其中任何一个结果都与case
表达式相同,每行返回一个值。
SELECT
HOST.a_display_label AS HOST,
MAX(CASE
WHEN
sof.a_display_label = 'HPS' THEN 'Y'
ELSE 'N'
END) AS HPS_INSTALLED,
MAX(CASE
WHEN
sof.a_display_label = 'PowerToken' THEN 'Y'
ELSE 'N'
END) AS PT_INSTALLED
FROM vcms.node_1 HOST
JOIN vcms.installed_software_1 sof
ON LOWER (sof.a_root_container) = LOWER (HOST.cmdb_id)
GROUP BY HOST.a_display_label
仅当基于a_display_label
条件的每join
行有一行时,结果才可靠。否则你仍会得到多行,在这种情况下聚合是不正确的。
答案 2 :(得分:0)
我只是意识到我的效率不如其他答案,但仅供参考。
请注意这是sql server,但oracle的工作相同
<强> SQL FIDDLE DEMO 强>
SELECT [Host],
CASE WHEN
COUNT( CASE WHEN [SW] = 'SW A' THEN 1 END) >= 1 THEN 'YES'
ELSE 'NO'
END as sw_a,
CASE WHEN
COUNT( CASE WHEN [SW] = 'SW B' THEN 1 END) >= 1 THEN 'YES'
ELSE 'NO'
END as sw_b
FROM hosts
GROUP BY [Host]
<强>输出强>