Почему «Где 1 <> 1» в запросе возвращает все строки? - PullRequest
6 голосов
/ 19 марта 2009

Я столкнулся с запросом в приложении, которое я унаследовал, и выглядит так:

Select *
From foo
where
    1 <> 1

Когда я это анализирую, он ничего не должен возвращать (1 <> 1 должен иметь значение false, верно). Однако (по крайней мере, на моем компьютере с Oracle) возвращается полный список всего в foo. Когда я пытаюсь сделать то же самое в MSAccess / Jet и MSSQL, я получаю ожидаемое поведение. Чем он отличается от Oracle (и почему первоначальный разработчик хотел бы это сделать)?

Примечание: я видел какое-то суеверие о + s и -s использования «где 1 = 1», и это вызывало полное сканирование таблицы; но я не думаю, что это был первоначальный разработчик.

Небольшое обновление:
В этом случае foo является представлением. Когда я пробую то же самое на реальной таблице, я получаю то, что ожидал (без строк).

Обновление 2:
Я следовал коду дальше по кроличьей норе и определил, что все, что он делает, пытается захватить названия полей / столбцов. Я все еще в растерянности относительно того, почему он возвращает полный набор записей; но только по взглядам.

Буквально он строит запрос в строке и передает его для выполнения другой функции без изменений.

'VB6
strSQL = "SELECT * FROM " & strTableName & " WHERE 1 <> 1"

В этом случае strTableName содержит имя представления.

Обновление 3:
Для справки, вот одна из точек зрения, с которыми у меня возникают проблемы. (Я изменил имена полей / таблиц / схем)

CREATE OR REPLACE FORCE VIEW scott.foo (field1,
                                        field2,
                                        field4,
                                        field5,
                                        field12,
                                        field8,
                                        field6,
                                        field7,
                                        field16,
                                        field11,
                                        field13,
                                        field14,
                                        field15,
                                        field17
                                       )
AS
   SELECT   bar.field1,
            bar.field2,
            DECODE
               (yadda.field9, NULL, 'N',
                DECODE (yadda.field3, NULL, 'Y', 'N')
               ) AS field4,
            bar.field5,
            snafu.field6,
            DECODE
                (snafu.field6,
                 NULL,
                bar.field8,
                   bar.field8
                 - snafu.field6
                ) AS field7,
            DECODE
               (yadda.field10,
                NULL,
            bar.field12,
                yadda.field10
               ) AS field11,
            DECODE
               (SIGN (  yadda.field10 - bar.field12),
                NULL, 'N', 1, 'N', 0, 'N', -1, 'Y'
               ) AS field13,
            bar.field14,
            ADD_MONTHS
               (DECODE (yadda.field10, NULL, bar.field12, yadda.field10
                       ),
                bar.field14 * 12
               ) AS field15,
       FROM clbuttic,
            bar,
            yadda,
            snafu
      WHERE clbuttic.asset_type = bar.asset_type
        AND bar.field16 = yadda.field9(+)
        AND bar.field1 = snafu.field1(+)
        AND (bar.field17 IS NULL)
   ;

Добавление Order By 1 (или имя некоторого столбца в списке выбора на foo), похоже, убеждает Oracle вернуть мне пустой набор. Это долгосрочное решение, но не краткосрочное (изменение кода и повторное развертывание - это главное PITA). Я надеюсь, что есть некоторые известные настройки на стороне DB или что-то не так в View, что является причиной этого странного поведения.

Ответы [ 15 ]

1 голос
/ 19 марта 2009

Обычно вы используете что-то подобное, когда хотите вернуть только все столбцы для таблицы SQL. Если это не работает в Oracle, вы можете попробовать что-то подобное неправильно, например:

Select *
From foo
where
    1 == 2

или, возможно,

where
    key < 0
1 голос
/ 19 марта 2009

WHERE 1 = 1 должен вызвать полное сканирование таблицы, точно так же, как полностью пропущено условие WHERE. Если вы извлекаете каждую строку из таблицы, конечно, это полное сканирование таблицы.

Я не могу комментировать информацию о том, что WHERE 1 <> 1 не работает должным образом в Oracle. Это звучит действительно неправильно. Вы уверены, что видели результат, который вы описываете из этого запроса? Попробуйте еще раз, чтобы быть уверенным.

0 голосов
/ 20 марта 2009

В связи с мыслями Коди Кастерлайн: столбец 1 в представлении может быть полон значений NULL? Если Oracle интерпретирует WHERE как «значение в столбце 1, не равное значению в столбце 1», а значение в столбце 1 равно NULL, мы попадаем в странный мир пустых значений SQL. На каждом диалекте SQL я знаю, что NULL = NULL не соответствует действительности. Возможно, Oracle решила, что значение NULL <> NULL должно быть истинным?

0 голосов
/ 20 марта 2009

Частичное решение

Обновите представление, добавив order by 1 после предложения where.

WHERE clbuttic.asset_type = bar.asset_type
    AND bar.field16 = yadda.field9(+)
    AND bar.field1 = snafu.field1(+)
    AND (bar.field17 IS NULL)
order by 1;

Он лечит симптом (и мне не нужно перекомпилировать и повторно развертывать код), но не говорит мне, почему я получаю это странное поведение.

Обновление: Выполнение заказа по строковой константе имеет тот же эффект, но не меняет план (как показано в плане объяснения). Я подозреваю, что этот порядок будет выполняться быстрее на 1 (который, я думаю, следует отсортировать по первому столбцу).

WHERE clbuttic.asset_type = bar.asset_type
    AND bar.field16 = yadda.field9(+)
    AND bar.field1 = snafu.field1(+)
    AND (bar.field17 IS NULL)
order by "a";
0 голосов
/ 20 марта 2009

SELECT, вероятно, не сломан. Сначала получите точную строку запроса, которая вызывает такое поведение. Запустите запрос непосредственно в БД, а не через приложение VB 6. Проблема все еще происходит? Иди оттуда.

...