2012-03-01 2 views
3

Похоже, что при использовании предложения having a count(*) оценивается до having, но после него оценивается количество возвращаемых строк. Исправление - это, вероятно, подзапросы, но если это можно избежать, я бы хотел. Я использую count(*), чтобы избежать no_data_found.Разница между количеством возвращаемых строк и количеством этих строк при использовании

Такое поведение наблюдается в 11.2.0.1.0, 10.2.0.1.0, 9.2.0.7.0, поэтому оно явно предназначено, но я не совсем понимаю, почему. Ниже приведен простой пример.

Кто-нибудь знает, почему это происходит? Я бы ожидал, что count(*) вернется 1.

create table tmp_test1 as 
    select level as id, level as val 
    from dual 
connect by level <= 1000 
     ; 

Table created. 

create table tmp_test2 as 
    select level as id, level as val 
    from dual 
connect by level <= 1000 
     ; 

Table created. 

select count(*) as count 
    from tmp_test1 a 
    join tmp_test2 b 
    on a.id = b.id 
having max(a.val) = max(b.val) 
     ; 

    COUNT 
---------- 
     1000 

select 1 as num_rows 
    from tmp_test1 a 
    join tmp_test2 b 
    on a.id = b.id 
having max(a.val) = max(b.val) 
     ; 

    NUM_ROWS 
---------- 
     1 
+0

В чем вопрос? Это абсолютно разумное и ожидаемое поведение для любой системы баз данных (с использованием SQL)! – Mithrandir

+0

@Ben - что вы ожидали, что он вернется? –

+0

@ Митрандир, не так ли? Я никогда не сталкивался с этим раньше ... Почему мой вопрос? Количество возвращаемых строк ясно указывает, что предложение having оценивается, но я не понимаю, почему счет оценивается ранее. – Ben

ответ

3

Предложение having работает на уровне группы - где не указана ни одна из групп с помощью, это означает, что он работает по всему набору данных.

Это означает, что в любом запросе с пунктом having и не group by пункта, результаты могут возвращать только 0 строк (если условие ложно having) или 1 ряд (если условие истинно having).

+0

+1, что делает какую-то логику ... – Ben

3

От documentation:

Когда GROUP BY не используется, HAVING ведет себя как ИНЕКЕ.

Так, это может быть что-то вроде этого:

select count(*) as count 
    from tmp_test1 a 
    join tmp_test2 b 
    on a.id = b.id 

Эта часть получит Вас 1000 для count и

having max(a.val) = max(b.val) 

поможет вам только одну запись.


В этом случае, поскольку он также даст вам одну запись.

select 1 as num_rows 
    from tmp_test1 a 
    join tmp_test2 b 
    on a.id = b.id 
having max(a.val) = max(b.val) 
     ; 
1

Вы думаете это неправильно ...

select count(*) as count 
    from tmp_test1 a 
    join tmp_test2 b 
    on a.id = b.id 

эта часть будет возвращать только одну строку со значением 1000

having max(a.val) = max(b.val) 

и эта часть будет применять то, что можно думать, как где условия за то, что вы ранее получили (поэтому он будет оцениваться только один раз), и как max (a) = max (b), он возвращает true.

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