Избегайте декартовых запросов - найдите правильное предложение where

Следующий код генерирует операторы alter password для изменения всех стандартных паролей в базе данных Oracle. В версии 12.1.0.2.0 больше невозможно изменить его на неверные значения пароля. Вот почему мне пришлось построить эту конструкцию корпуса переключателя. Жаба выдает предупреждение (правило 5807) о конструкции соединения в конце. В нем говорится: «Избегайте декартовых запросов — используйте предложение where...». Любые идеи о предложении «где», которое работает на всех версиях базы данных оракула?

SET TERMOUT  OFF
SET ECHO     OFF
SET LINESIZE 140
SET FEEDBACK OFF
SET PAGESIZE 0

SPOOL user.sql

SELECT    'alter user '
       || username
       || ' identified by values '
       || CHR (39)
       || CASE
             WHEN b.version = '12.1.0.2.0' THEN '462368EA9F7AD215'
             ELSE 'Invalid Password'
          END
       || CHR (39)
       || ';'
  FROM DBA_USERS_WITH_DEFPWD a,
       (SELECT DISTINCT version
          FROM PRODUCT_COMPONENT_VERSION) b;

SPOOL OFF
@user.sql

person r0tt    schedule 08.04.2016    source источник
comment
Вам нужна запись, возвращаемая запросом для каждого пользователя и каждой версии компонента продукта? Или есть комбинации, которые вы не хотите возвращать?   -  person Stefan Steinegger    schedule 08.04.2016
comment
самый простой способ, который не добавляет никаких накладных расходов (кроме вполне корректного утверждения о реорганизации запроса в соответствии со стандартами SQL 92), — добавить в запрос where 1 = 1.   -  person T Gray    schedule 08.04.2016


Ответы (4)


На моей машине (ноутбук с бесплатной XE-версией Oracle — возможно простейшее расположение) таблица PRODUCT_COMPONENT_VERSION имеет ЧЕТЫРЕ строки, а не одну. Существуют версии для разных продуктов, включая Oracle Database и PL/SQL. На моей машине версия одинакова во всех четырех рядах, но я не понимаю, почему этого вообще следует ожидать.

Если они могут быть разными, СНАЧАЛА вы можете игнорировать все ответы, которые говорят вам, что перекрестное соединение не является проблемой, потому что вы возвращаете только одну строку. Вы не; вы можете вернуть более одной строки. ВТОРОЕ, почему в самом запросе вы возвращаете версию из ВСЕХ строк PRODUCT_COMPONENT_VERSION, а не только версию для базы данных Oracle? Я представляю что-то вроде

WHERE PRODUCT LIKE 'Oracle%'

должно работать - и вам не понадобится DISTINCT в предложении SELECT. Удачи!

person mathguy    schedule 08.04.2016
comment
Это хорошая идея - другой пример: WHERE UPPER (product) LIKE '%DATABASE% - person r0tt; 11.04.2016

Жаба просто предупреждает вас о том, что вы выполняете соединение без JOIN условий. В данном случае вы действительно это делаете, но одна из задействованных сущностей (запрос от PRODUCT_COMPONENT_VERSION) должна возвращать только одно значение, поэтому проблема ложная. Вы выполняете декартову операцию с сущностью, которая имеет только 1 элемент, поэтому она является декартовой, но не умножает ваши значения.

person Aleksej    schedule 08.04.2016

Вместо того, чтобы использовать старый синтаксис соединения (без условия соединения, о чем предупреждает Жаба), вы можете использовать синтаксис соединения (ANSI/ISO) SQL-92 и явно указать, что соединение является CROSS JOIN:

SELECT    'alter user '
       || username
       || ' identified by values '
       || CHR (39)
       || CASE
             WHEN b.version = '12.1.0.2.0' THEN '462368EA9F7AD215'
             ELSE 'Invalid Password'
          END
       || CHR (39)
       || ';'
  FROM DBA_USERS_WITH_DEFPWD a
       CROSS JOIN
       (SELECT DISTINCT version
          FROM PRODUCT_COMPONENT_VERSION) b;

Поскольку вторая объединенная таблица вернет только одну строку, вы не увеличите количество возвращаемых строк, а CROSS JOIN не ожидает условия соединения (поэтому, надеюсь, Toad перестанет напрасно жаловаться).

Немного более эффективная версия (но она минимальна, поскольку задействовано не так много строк) будет использовать:

SELECT version FROM PRODUCT_COMPONENT_VERSION WHERE ROWNUM = 1

Тогда Oracle может прекратить чтение из таблицы после первой строки и не должен выполнять операцию DISTINCT.

person MT0    schedule 08.04.2016

Если вам нужны все комбинации пользователей и компонентов продукта, декартово произведение — правильный выбор. Следите за количеством строк, которые потенциально могут быть записаны в файл (пользователи * версии компонента). Вероятно, вам нужна какая-то пакетная обработка.

person Stefan Steinegger    schedule 08.04.2016