没有数据的 SQL CASE 语句

Posted

技术标签:

【中文标题】没有数据的 SQL CASE 语句【英文标题】:SQL CASE Statement for no data 【发布时间】:2015-02-10 22:14:55 【问题描述】:

我有一个表,其中的进程引擎 1、2、3、4、5、6 处于运行状态。当其中一个引擎关闭时,记录将从表中删除。使用 case 语句,我可以显示第一个已关闭的引擎,但如果 2 个或更多引擎已关闭,我该如何显示这些引擎。例如如果两个引擎都关闭,我如何让这个查询显示 PE 2 IS DOWN 和 PE 4 is DOWN。现在它只显示列表中第一个关闭的引擎。

    SELECT CASE
WHEN (SELECT COUNT(PE_ID) FROM CWVMINFO WHERE PE_ID = 1) = 0 THEN 'PE 1 IS DOWN'
WHEN (SELECT COUNT(PE_ID) FROM CWVMINFO WHERE PE_ID = 2) = 0 THEN 'PE 2 IS DOWN'
WHEN (SELECT COUNT(PE_ID) FROM CWVMINFO WHERE PE_ID = 3) = 0 THEN 'PE 3 IS DOWN'
WHEN (SELECT COUNT(PE_ID) FROM CWVMINFO WHERE PE_ID = 4) = 0 THEN 'PE 4 IS DOWN'
WHEN (SELECT COUNT(PE_ID) FROM CWVMINFO WHERE PE_ID = 5) = 0 THEN 'PE 5 IS DOWN'
WHEN (SELECT COUNT(PE_ID) FROM CWVMINFO WHERE PE_ID = 6) = 0 THEN 'PE 6 IS DOWN'
ELSE 'ALL PROCESS ENGINES ARE UP AND RUNNING'
END "STATUS"
from dual;

【问题讨论】:

您使用的是什么数据库?可以根据数据库制作更有针对性的脚本。 @ps2goat dual 通常是oracle 我使用的是 ORACLE 11.2.0 @Lashane,谢谢,我从来没有在那个级别上使用过 Oracle。我以为他只是为他的桌子命名。 最好的起点是创建一个包含流程引擎列表的表。如果您有一个权威的列表开始,编写查询以确定它们的状态会变得更加简单。 【参考方案1】:

而不是大小写,使用union all 处理两种不同的情况,所有情况都很好,有些没有运行。子查询分解,减少重复代码。

with engines as (select level as engine_number 
    from dual 
    connect by level <= 6)
, down_engines as (select engine_number
    from engines
    where engine_number not in (select pe_id from cwvminfo))
select to_char(engine_number) || ' IS DOWN'
from down_engines 
union all
select 'all engines are running'
from dual
where not exists (select null from down_engines)

【讨论】:

非常感谢香农!这就像一个魅力,正是我所需要的!谢谢!【参考方案2】:

我会使用单个查询和条件聚合来重写它:

select coalesce(case when sum(case when pe_id = 1 then 1 else 0 end) = 0
                     then 'PE 1 IS DOWN; '
                end) ||
               (case when sum(case when pe_id = 1 then 2 else 0 end) = 0
                     then 'PE 2 IS DOWN; '
                end) ||
               (case when sum(case when pe_id = 1 then 3 else 0 end) = 0
                     then 'PE 3 IS DOWN; '
                end) ||
               (case when sum(case when pe_id = 1 then 4 else 0 end) = 0
                     then 'PE 4 IS DOWN; '
                end) ||
               (case when sum(case when pe_id = 1 then 5 else 0 end) = 0
                     then 'PE 5 IS DOWN; '
                end) ||
               (case when sum(case when pe_id = 1 then 6 else 0 end) = 0
                     then 'PE 6 IS DOWN; '
                end), 'ALL PROCESS ENGINES ARE UP AND RUNNING') as status
from CWVMINFO;

或者,如果您不必只有一行,您可以这样做:

select ids.id,
       (case when count(c.pe_id) = 0 then "DOWN' else 'UP' end) as status
from (select 1 as id from dual union all select 2 from dual union all select 3 from dual union all
      select 4 union all select 5 union all select 6 from dual
     ) ids left join
     CWVMINFO c
     on c.pe_id = ids.id
group by ids.id
order by ids.id;

这会让一切都在检查中变得更加明显。

【讨论】:

非常感谢 Gordon!【参考方案3】:

我会为您在这里遇到的每个案例编写一个带有 if 条件的存储过程。

【讨论】:

【参考方案4】:

您可以尝试以下方法。这有点笨拙,但我认为它可能会起作用。

WITH p1 AS (
    SELECT LEVEL AS pe_id
      FROM dual
   CONNECT BY LEVEL <= 6
)
SELECT DISTINCT CASE WHEN all_ind = 0 THEN 'ALL PROCESS ENGINES ARE UP AND RUNNING'
  WHEN process_cnt = 0 THEN 'PE ' || pe_id || ' IS DOWN' END AS status
  FROM (
    SELECT pe_id, process_cnt
         , SUM(DECODE(process_cnt, 0, 1, 0)) OVER ( ) AS all_ind
      FROM (
        SELECT p1.pe_id, COUNT(c1.pe_id) AS process_cnt
          FROM p1 LEFT JOIN cwvminfo c1
            ON p1.pe_id = c1.pe_id
         GROUP BY p1.pe_id
    )
)

Please see SQL Fiddle here.

【讨论】:

非常感谢大卫!由于某种原因,查询在结果集中提取了一个空值,但我可以只处理空值并获取其余数据。 它将拉取NULL。我会做一些事情来过滤掉它,但我不想深入了解子查询。【参考方案5】:

您可以使用多个CASE 表达式来为每个表达式返回状态:

WITH cte AS (
SELECT CASE WHEN (SELECT COUNT(PE_ID) FROM CWVMINFO WHERE PE_ID = 1) = 0 THEN 'PE 1 IS DOWN' END AS PE_1
      ,CASE WHEN (SELECT COUNT(PE_ID) FROM CWVMINFO WHERE PE_ID = 2) = 0 THEN 'PE 2 IS DOWN' END AS PE_2
      ,CASE WHEN (SELECT COUNT(PE_ID) FROM CWVMINFO WHERE PE_ID = 3) = 0 THEN 'PE 3 IS DOWN' END AS PE_3
      ,CASE WHEN (SELECT COUNT(PE_ID) FROM CWVMINFO WHERE PE_ID = 4) = 0 THEN 'PE 4 IS DOWN' END AS PE_4
      ,CASE WHEN (SELECT COUNT(PE_ID) FROM CWVMINFO WHERE PE_ID = 5) = 0 THEN 'PE 5 IS DOWN' END AS PE_5
      ,CASE WHEN (SELECT COUNT(PE_ID) FROM CWVMINFO WHERE PE_ID = 6) = 0 THEN 'PE 6 IS DOWN' END AS PE_6
       from dual)
SELECT *,CASE WHEN COALESCE(PE_1,PE_2,PE_3,PE_4,PE_5,PE_6) IS NULL THEN 'ALL PROCESS ENGINES ARE UP AND RUNNING' END "STATUS"
FROM cte

【讨论】:

我认为您的备用查询不会起作用...不会有任何行具有特定值 PE_ID 仅供参考 ...您的 CTE 中需要 FROM dual 非常感谢哈特!由于某种原因无法找到 FROM 关键字错误,但我对如何处理这些类型的查询有了基本的了解。 @ram81012 也许from dual 实际上没有必要?遗憾的是,我无法对其进行测试以进行故障排除。【参考方案6】:

您可以使用COALESCELISTAGG

SELECT COALESCE(
         LISTAGG('PE ' || pe_id || ' IS DOWN', ' and ')
           WITHIN GROUP (ORDER BY pe_id),
         'ALL PROCESS ENGINES ARE UP AND RUNNING'
       ) AS status
FROM   (
  SELECT DISTINCT pe_id
  FROM   CWVMINFO
)

其中,对于样本数据:

CREATE TABLE CWVMINFO (pe_id NUMBER);

输出:

STATUS
ALL PROCESS ENGINES ARE UP AND RUNNING

如果你:

INSERT INTO CWVMINFO (pe_id) VALUES (1);

然后输出:

STATUS
PE 1 IS DOWN

那么,如果你:

INSERT INTO CWVMINFO (pe_id) VALUES (3);

然后输出:

STATUS
PE 1 IS DOWN and PE 3 IS DOWN

db小提琴here

【讨论】:

以上是关于没有数据的 SQL CASE 语句的主要内容,如果未能解决你的问题,请参考以下文章

SQL语句中case,when,then的用法

没有值时带有 CASE 的 SQL 语句

CASE 语句 SQL 中返回多列

SQL nvl 等效 - 没有 if/case 语句 & isnull & coalesce

SQL语句中Case 的用法

sql中的case语句对齐和清理