使用CASE语句问题选择数据

时间:2016-07-19 13:49:48

标签: sql oracle select join case

我目前正在尝试制定查询以确定是否在所述主机上安装了某些软件应用程序。我们在数据库中的表是以包含主机名和软件的列的方式设置的,例如,可能有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

我想知道返回“预期结果”数据需要哪些其他信息。提前谢谢。

3 个答案:

答案 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表达式上使用mincase,因为其中任何一个结果都与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]

<强>输出

enter image description here