Как получить значение 0, когда count (*) возвращает ноль при умножении значений - PullRequest
4 голосов
/ 29 июня 2010

У меня есть таблица, которая содержит коды ошибок и время входа (среди прочего).
Мне нужен способ подсчета количества строк с тем же кодом ошибки (который я выбрал) за последний час,и для вывода результата код ошибки.

SELECT COUNT(*) || ',' || error_code as amount_and_code
FROM my_table
WHERE error_code in (5001, 5002, 5003, 5004, 5005)
AND entry_date >= (SYSDATE - 1/24)
group by error_code;

Я получаю очевидный результат

AMOUNT_AND_CODE
---------------
4,5001
1,5002
2,5005

И мой вопрос: как я могу также вернуть 0,error_code для значений, которые былине найден.
Что я хочу получить, это

AMOUNT_AND_CODE
---------------
4,5001
1,5002
0,5003
0,5004
2,5005

Есть ли способ получить результат, который я ищу?

Огромная благодарность за вашу помощь, мод.

Редактировать: у меня нет таблицы, содержащей все коды ошибок.
Редактировать2: Oracle8i Enterprise Edition, выпуск 8.1.7.4.0

Ответы [ 7 ]

5 голосов
/ 29 июня 2010

Вы можете попробовать что-то вроде этого:

SQL> create table nnn(error_code varchar2(4), entry_date date);

Table created.

SQL> insert into nnn values (5001, sysdate);

1 row created.

SQL> insert into nnn values (5003, sysdate - 10);

1 row created.

SQL>
SQL> with tbl as
  2  (select 5001 error_code from dual union all
  3   select 5002 error_code from dual union all
  4   select 5003 error_code from dual union all
  5   select 5004 error_code from dual)
  6  select count(nnn.error_code), tbl.error_code
  7  from   nnn, tbl
  8  where  nnn.error_code(+) = tbl.error_code
  9  and    entry_date(+) >= (SYSDATE - 1/24)
 10  group  by tbl.error_code;

COUNT(NNN.ERROR_CODE) ERROR_CODE
--------------------- ----------
                    0       5003
                    1       5001
                    0       5002
                    0       5004

SQL>
4 голосов
/ 29 июня 2010

У вас есть таблица кодов ошибок? Если так, то вы можете сделать это:

SELECT COUNT(my_table.id) || ',' || e.error_code as amount_and_code
FROM error_codes e
LEFT OUTER JOIN my_table ON my_table.error_code = e.error_code
                        AND my_table.entry_date >= (SYSDATE - 1/24)
WHERE e.error_code in (5001, 5002, 5003, 5004, 5005)
group by e.error_code;

Если нет, то попробуйте:

WITH error_codes as
    ( SELECT 5001 FROM DUAL
      UNION ALL
      SELECT 5002 FROM DUAL
      UNION ALL
      SELECT 5003 FROM DUAL
      UNION ALL
      SELECT 5004 FROM DUAL
      UNION ALL
      SELECT 5005 FROM DUAL
    )
SELECT COUNT(my_table.id) || ',' || e.error_code as amount_and_code
FROM error_codes e
LEFT OUTER JOIN my_table ON my_table.error_code = e.error_code
                        AND my_table.entry_date >= (SYSDATE - 1/24)
group by e.error_code;
2 голосов
/ 30 июня 2010

Я надеюсь, что entry_date >= (SYSDATE - 1/24) фильтрует записи, которые были вам нужны (то есть 5003 и 5004).

После того, как удалите это условие и проверьте результат.

или

Попробуйте ниже запрос, это может решить вашу проблему

SELECT COUNT(error_code) || ',' || error_code as amount_and_code 
    FROM my_table 
    WHERE error_code in (5001, 5002, 5003, 5004, 5005) AND 
          entry_date >= (SYSDATE - 1/24) 
GROUP BY error_code; 
2 голосов
/ 29 июня 2010

Всегда ли коды ошибок будут в порядке?Вы должны быть в состоянии использовать соединение с помощью в этом случае следующим образом:

   SELECT COUNT(MY_TABLE.ERROR_CODE) || ',' || ERROR_CODES.error_code as amount_and_code
FROM 
    (
        SELECT (5000+LEVEL) error_code 
        FROM DUAL 
        CONNECT BY LEVEL <= 5    
    ) ERROR_CODES
    LEFT JOIN
    (
        SELECT 5001 ERROR_CODE, (SYSDATE - 1/26) ENTRY_DATE FROM DUAL
        UNION ALL
        SELECT 5001 ERROR_CODE, (SYSDATE - 1/26) ENTRY_DATE FROM DUAL
        union all
        SELECT 5001 ERROR_CODE, (SYSDATE - 1/26) ENTRY_DATE FROM DUAL
        union all
        SELECT 5001 ERROR_CODE, (SYSDATE - 1/26) ENTRY_DATE FROM DUAL
        union all
        SELECT 5002 ERROR_CODE, (SYSDATE - 1/26) ENTRY_DATE FROM DUAL
        union all
        SELECT 5005 ERROR_CODE, (SYSDATE - 1/26) ENTRY_DATE FROM DUAL
        UNION all
        SELECT 5005 ERROR_CODE, (SYSDATE - 1/26) ENTRY_DATE FROM DUAL
    ) MY_TABLE
      ON MY_TABLE.ERROR_CODE        = ERROR_CODES.ERROR_CODE
           AND MY_TABLE.ENTRY_DATE >= (SYSDATE - 1/24)
GROUP BY       ERROR_CODES.ERROR_CODE
order by  ERROR_CODES.error_code
;

, если вы просто хотите показать все ошибки, вы можете попробовать это

with MY_TABLE as(
        SELECT 5001 ERROR_CODE, (SYSDATE - 1/26) ENTRY_DATE FROM DUAL
        UNION ALL
        SELECT 5001 ERROR_CODE, (SYSDATE - 1/26) ENTRY_DATE FROM DUAL
        union all
        SELECT 5001 ERROR_CODE, (SYSDATE - 1/26) ENTRY_DATE FROM DUAL
        union all
        SELECT 5001 ERROR_CODE, (SYSDATE - 1/26) ENTRY_DATE FROM DUAL
        union all
        SELECT 5002 ERROR_CODE, (SYSDATE - 1/26) ENTRY_DATE FROM DUAL
        union all
        SELECT 5005 ERROR_CODE, (SYSDATE - 1/26) ENTRY_DATE FROM DUAL
        UNION ALL
        SELECT 5005 ERROR_CODE, (SYSDATE - 1/26) ENTRY_DATE FROM DUAL
        UNION ALL
        SELECT 5003 ERROR_CODE, (SYSDATE - 1/23) ENTRY_DATE FROM DUAL
        UNION ALL
        SELECT 5004 ERROR_CODE, (SYSDATE - 1/23) ENTRY_DATE FROM DUAL
        UNION ALL
        SELECT 5006 ERROR_CODE, (SYSDATE - 1/23) ENTRY_DATE FROM DUAL
        UNION ALL
        SELECT 5010 ERROR_CODE, (SYSDATE - 1/23) ENTRY_DATE FROM DUAL
        UNION ALL
        SELECT 6018 ERROR_CODE, (SYSDATE - 1/23) ENTRY_DATE FROM DUAL        
) 
 SELECT COUNT(MY_TABLE.ERROR_CODE) || ',' || ERROR_CODES.error_code as amount_and_code
FROM 
    (
        SELECT DISTINCT ERROR_CODE
        FROM MY_TABLE --**warning** this could be resource intensive    
    ) ERROR_CODES
    LEFT JOIN
     MY_TABLE
      ON MY_TABLE.ERROR_CODE        = ERROR_CODES.ERROR_CODE
           AND MY_TABLE.ENTRY_DATE >= (SYSDATE - 1/24)
GROUP BY       ERROR_CODES.ERROR_CODE
order by  ERROR_CODES.error_code
;

Это действительно просто даетВы различаете все коды ошибок в таблице, а затем выбираете счетчик на основе времени

        (
        SELECT DISTINCT ERROR_CODE
        FROM MY_TABLE --**warning** this could be resource intensive    
    ) ERROR_CODES

. Обратите внимание, это может быть ресурсоемким

, если вам нужны только конкретные числа= 5001,5002,5003, ####, #### 2, ..., ### x), тогда вы можете попробовать что-то вроде этого (для этого требуется создать пользовательский тип и функцию):

--see  http://asktom.oracle.com/pls/asktom/f?p=100:11:0::::P11_QUESTION_ID:210612357425
--create a table of numbers ,create a function to split the "where" into a table
--then return the data
CREATE OR REPLACE type numberTableType as table      of number;
/
create or replace function in_number(  p_string in varchar2 ) return numberTableType  AS
        l_string        long default p_string || ',';
        l_data          numberTableType := numberTableType();
        l_number        number ;
        N               NUMBER;
    BEGIN

      loop
          exit when l_string is null;
          n := instr( l_string, ',' );
         l_data.extend;
         begin --is user inputs a non-numeric value  skip the value
            l_number := cast(ltrim( rtrim( substr( l_string, 1, n-1 ) ) )  as number);
            l_data(l_data.count) := l_number ;
            EXCEPTION
                    WHEN VALUE_ERROR THEN
                        l_number := 0;
                    WHEN OTHERS THEN
                        raise ;
         end ;
         l_string := substr( l_string, n+1 );
    end loop;
    RETURN L_DATA;
  END in_number;
  /

 SELECT COUNT(MY_TABLE.ERROR_CODE) || ',' || ERROR_CODES.error_code as amount_and_code
FROM 
    (
        SELECT COLUMN_VALUE AS ERROR_CODE 
          from table(in_number('5001,5002,5003,5004,5005,5010'))    
    ) ERROR_CODES
    LEFT JOIN
        (
            SELECT 5001 ERROR_CODE, (SYSDATE - 1/26) ENTRY_DATE FROM DUAL
            UNION ALL
            SELECT 5001 ERROR_CODE, (SYSDATE - 1/26) ENTRY_DATE FROM DUAL
            union all
            SELECT 5001 ERROR_CODE, (SYSDATE - 1/26) ENTRY_DATE FROM DUAL
            union all
            SELECT 5001 ERROR_CODE, (SYSDATE - 1/26) ENTRY_DATE FROM DUAL
            union all
            SELECT 5002 ERROR_CODE, (SYSDATE - 1/26) ENTRY_DATE FROM DUAL
            union all
            SELECT 5005 ERROR_CODE, (SYSDATE - 1/26) ENTRY_DATE FROM DUAL
            UNION ALL
            SELECT 5005 ERROR_CODE, (SYSDATE - 1/26) ENTRY_DATE FROM DUAL
            UNION ALL
            SELECT 5003 ERROR_CODE, (SYSDATE - 1/23) ENTRY_DATE FROM DUAL
            UNION ALL
            SELECT 5004 ERROR_CODE, (SYSDATE - 1/23) ENTRY_DATE FROM DUAL
            UNION ALL
            SELECT 5006 ERROR_CODE, (SYSDATE - 1/23) ENTRY_DATE FROM DUAL
            UNION ALL
            SELECT 5010 ERROR_CODE, (SYSDATE - 1/23) ENTRY_DATE FROM DUAL
            UNION ALL
            SELECT 6018 ERROR_CODE, (SYSDATE - 1/23) ENTRY_DATE FROM DUAL            
        )
     MY_TABLE
      ON MY_TABLE.ERROR_CODE        = ERROR_CODES.ERROR_CODE
           AND MY_TABLE.ENTRY_DATE >= (SYSDATE - 1/24)
GROUP BY       ERROR_CODES.ERROR_CODE
ORDER BY  ERROR_CODES.ERROR_CODE
;  
2 голосов
/ 29 июня 2010

Вы пробовали ...

SELECT NVL (COUNT(*), 0) || ',' || error_code as amount_and_code
    FROM my_table
    WHERE error_code in (5001, 5002, 5003, 5004, 5005) AND
          entry_date >= (SYSDATE - 1/24)
GROUP BY error_code;
1 голос
/ 30 июня 2010

Сделайте запрос, как если бы у вас была внешняя таблица, без 'WITH', недоступной в Oracle 8 ... Очень похоже на код Тони:

SELECT COUNT(t1.error_code) || ',' || t2.error_code as amount_and_code
FROM my_table t right outer join 
                    (
                        select 5001 as error_code from dual
                        union
                        select 5002 as error_code from dual
                        union
                        select 5003 as error_code from dual
                        union
                        select 5004 as error_code from dual
                        union
                        select 5005 as error_code from dual
                    ) t2 on t1.error_code = t2.error_code
                         and t.entry_date >= (SYSDATE - 1/24)
group by t2.error_code;
0 голосов
/ 29 июня 2010

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...