2016-12-01 1 views
2

(*) Я использую эту команду, чтобы получить статус:Включить 0 в кол-функции SQL

SELECT DECODE(processed,1,'Complete', 'Incomplete') Last_Day_Report_Status,  
     COUNT(*) 
FROM Table_demo 
WHERE run_datetime >= trunc(sysdate)-1 
    AND run_datetime < trunc(sysdate) 
GROUP BY DECODE(processed,1,'Complete','Incomplete'); 

Он должен дать выход следующим образом:

Complete: 120

Неполная: 0

но это дает только: Complete: 120

ответ

5
WITH parameter as (
    SELECT 'Complete' as status FROM DUAL 
    UNION ALL 
    SELECT 'Incomplete' as status FROM DUAL 
) 
SELECT parameter.status as Last_Day_Report_Status,  
     COUNT(status) 
FROM parameter 
LEFT JOIN Table_demo 
    ON parameter.status = DECODE(status ,1,'Complete', 'Incomplete') 
WHERE run_datetime >= trunc(sysdate)-1 
    AND run_datetime < trunc(sysdate) 
GROUP BY parameter.status; 
0

Преимущество этого решения должно быть скорость. Он суммирует Table_demo в одну строку, что экономит потребность в вычисленном соединении для каждой используемой таблицы Table_demo.

SELECT 
    Last_Day_Report_Status, 
    DECODE(Last_Day_Report_Status, 'Complete', NVL(Completed,0), NVL(Total-Completed,0)) counts 
FROM 
    (SELECT 'Complete' Last_Day_Report_Status FROM DUAL 
    UNION ALL 
    SELECT 'Incomplete' Last_Day_Report_Status FROM DUAL 
    ) 
    OUTER APPLY 
    (SELECT COUNT(DECODE(processed,1,'Complete')) Completed, COUNT(1) Total 
    FROM Table_demo 
    WHERE run_datetime >= TRUNC(SYSDATE)-1 
     AND run_datetime < TRUNC(SYSDATE) 
); 

Большая проблема с этим оптимизатор отказывается обрабатывать COUNTS подзапрос первым или сделать как хеш-объединение, даже когда намекнул на смерть, в результате чего суммирования будет работать в два раза, комментарии приветствуются. Наиболее явная оптимизация запроса у меня есть (несмотря на уродливую подделкой присоединиться к 1 = 1), который, к сожалению, до сих пор вложенной-петли от союза к суммированию, является:

SELECT /*+ ordered */ 
    Last_Day_Report_Status, 
    DECODE(Last_Day_Report_Status, 'Complete', NVL(Completed,0), NVL(Total-Completed,0)) counts 
FROM 
    (SELECT COUNT(DECODE(processed,1,'Complete')) Completed, COUNT(1) Total 
    FROM Table_demo 
    WHERE run_datetime >= TRUNC(SYSDATE)-1 
     AND run_datetime < TRUNC(SYSDATE) 
) 
    RIGHT OUTER JOIN 
(SELECT 'Complete' Last_Day_Report_Status FROM DUAL 
    UNION ALL 
    SELECT 'Incomplete' Last_Day_Report_Status FROM DUAL 
) ON 1=1; 

Оптимизатор чувствовал себя неспособным использовать подсказка ORDERED, которая запрашивает, что подзапросы выполняются в том порядке, в котором они записаны.

Учитывая путь оптимизации и при условии, что Table_demo может быть большим, суммирование может быть реализовано (предварительно консервировано). Процесс материализации имеет начальные затраты, поэтому может быть дорогостоящим в цикле, который выполняет 100 или 1000 раз в секунду. Несмотря на то, что запрос на материализованный запрос дважды запрашивается (один раз для каждой строки объединения), по-прежнему требуется недокументированный намек INLINE ed, стандарт ROWNUM в SELECT, чтобы заставить это работать не будет, поскольку он знает, что только собирается быть одной строкой. Это дает хорошую оптимизацию:

WITH counts AS 
    (SELECT /*+ MATERIALIZE */ COUNT(DECODE(processed,1,'Complete')) Completed, COUNT(1) Total 
    FROM Table_demo 
    WHERE run_datetime >= TRUNC(SYSDATE)-1 
     AND run_datetime < TRUNC(SYSDATE) 
) 
SELECT 
    Last_Day_Report_Status, 
    DECODE(Last_Day_Report_Status, 'Complete', NVL(Completed,0), NVL(Total-Completed,0)) counts 
FROM 
    (SELECT 'Complete' Last_Day_Report_Status FROM DUAL 
    UNION ALL 
    SELECT 'Incomplete' Last_Day_Report_Status FROM DUAL 
    ) 
    OUTER APPLY 
    counts; 

Версия оптимизатора, которую я использую, - это Oracle 12.1.0.1 SE. Я принял планы объяснения по номиналу, не проверяя трассировку выполнения.

Смежные вопросы