2013-09-18 4 views
0

Следующий PL-код/​​SQL ведет себя по-другому, если WHERE выглядит следующим образом:Проверьте строки существуют

WHERE USERNAME = 'aaaaaa' 

и по-разному, если выглядит следующим образом:

WHERE USERNAME = userName 

Почему результат не то же самое если userName := 'aaaaaa'? Что я делаю не так? Спасибо!

declare 
    isFound NUMBER; 
    userName VARCHAR2(30); 
begin 
    isFound := 0; 
    userName := 'aaaaaa'; 

    SELECT COUNT(*) 
    INTO isFound 
    FROM MyTable 
    WHERE USERNAME = 'aaaaaa' -- userName 
    AND ROWNUM = 1; 

    IF isFound > 0 THEN 
    dbms_output.put_line('Found'); 
    ELSE 
    dbms_output.put_line('Not found'); 
    END IF; 

end; 
+1

вы не можете wrrite ROWNUM = 1, а следует использовать ROWNUM <2 – Harshit

+4

@Harshit - [да вы можете] (http://sqlfiddle.com/#!4/da67e/1); '1' - единственное значение, которое вы * можете * использовать' = 'с. 'rownum = 2' никогда не найдет никаких строк, потому что это неверно для первой найденной строки; но 'rownum = 1' * is * true для первой найденной строки (а не для второй), так что это нормально. Однако использование '<2' может сделать код более последовательным ... –

+0

+1 для использования plsqldeveloper, но -1 для того, чтобы не использовать легкий легкий отладчик. –

ответ

4

В этой версии:

SELECT COUNT(*) 
    INTO isFound 
    FROM MyTable 
    WHERE USERNAME = userName 
    AND ROWNUM = 1; 

... USERNAME колонке таблицы сравнивается с самим собой, так что он всегда будет соответствовать. Вы не сравниваете его с локальной переменной. Если вы хотите сделать это, вам нужно дать переменной другое имя столбца:

declare 
    isFound NUMBER; 
    localUserName VARCHAR2(30); 
begin 
    isFound := 0; 
    userName := 'aaaaaa'; 

    SELECT COUNT(*) 
    INTO isFound 
    FROM MyTable 
    WHERE USERNAME = localUserName 
    AND ROWNUM = 1; 

    IF isFound > 0 THEN 
    dbms_output.put_line('Found'); 
    ELSE 
    dbms_output.put_line('Not found'); 
    END IF; 

end; 

Или, как говорит Дэвид Олдридж, использовать метку, чтобы отличить локальную переменную из колонки таблицы:

<<local>> 
declare 
    isFound NUMBER; 
    userName MyTable.USERNAME%TYPE; 
begin 
    isFound := 0; 
    userName := 'aaaaaa'; 

    SELECT COUNT(*) 
    INTO isFound 
    FROM MyTable 
    WHERE USERNAME = local.userName 
    AND ROWNUM = 1; 
... 

Вы также можете использовать этот подход с именованными блоками; если это было внутри функции, вы можете ссылаться на локальную переменную как function_name.variable_name. Поскольку это анонимный блок, эта метка играет ту же роль, что и function_name.

В документации имеется a section about name resolution.

+1

+1, а также подумайте об именовании блока <> и префикс переменной с ним в SQL как «WHERE USERNAME = MY_NAME.USERNAME» вместо;) –

+0

@DavidAldridge - это вариант, который мне действительно нужно рассмотреть чаще, особенно в именованные блоки, вместо использования префикса для локального имени (я знаю, что это один из ваших ошибок * 8-). –

+0

Один из моих * много * bugbears :) –

2

Вы можете использовать этикетку.

<<the_code>> 
declare 
    isFound NUMBER; 
    userName VARCHAR2(30); 
begin 
    isFound := 0; 
    userName := 'aaaaaa'; 

    SELECT COUNT(*) 
    INTO isFound 
    FROM MyTable 
    WHERE USERNAME = the_code.userName 
    AND ROWNUM = 1; 

    IF isFound > 0 THEN 
    dbms_output.put_line('Found'); 
    ELSE 
    dbms_output.put_line('Not found'); 
    END IF; 

end; 
+0

спасибо вам также! – dee

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