SQL 没有数据的 CASE 语句
SQL CASE Statement for no data
我有一个 table 进程引擎 1,2,3,4,5,6,状态为 运行。当其中一个引擎停机时,记录将从 table 中删除。使用 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;
您可以使用多个 CASE
表达式来 return 每个状态:
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
我会为这里的每个案例编写一个带有 if 条件的存储过程。
您可以尝试以下方法。这有点笨拙,但我认为它可能会起作用。
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
)
)
而不是大小写,使用 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)
我会使用单个查询和条件聚合重写它:
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;
这将使一切都在检查中变得更加明显。
您可以使用 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<>fiddle here
我有一个 table 进程引擎 1,2,3,4,5,6,状态为 运行。当其中一个引擎停机时,记录将从 table 中删除。使用 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;
您可以使用多个 CASE
表达式来 return 每个状态:
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
我会为这里的每个案例编写一个带有 if 条件的存储过程。
您可以尝试以下方法。这有点笨拙,但我认为它可能会起作用。
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
)
)
而不是大小写,使用 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)
我会使用单个查询和条件聚合重写它:
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;
这将使一切都在检查中变得更加明显。
您可以使用 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<>fiddle here