没有数据的 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;
【问题讨论】:
您使用的是什么数据库?可以根据数据库制作更有针对性的脚本。 @ps2goatdual
通常是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】:
您可以使用COALESCE
和LISTAGG
:
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 语句的主要内容,如果未能解决你的问题,请参考以下文章