避免使用笛卡儿查询 - 找到合适的“where子句”

时间:2016-04-08 12:00:52

标签: sql oracle cartesian

以下代码生成alter password语句以更改Oracle数据库中的所有标准密码。在版本12.1.0.2.0中,不再可能将其更改为无效的密码值。这就是我必须构建这个switch case结构的原因。 Toad在结尾处对连接构造发出警告(规则5807)。它说“避免使用cartesian查询 - 使用where子句......”。关于“where子句”的所有想法都适用于所有oracle数据库版本?

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

3 个答案:

答案 0 :(得分:2)

Toad只是给你一个警告,说明你正在进行没有JOIN条件的连接。 在这种情况下,您实际上是这样做的,但其中一个涉及的实体(来自PRODUCT_COMPONENT_VERSION的查询)应该只返回一个值,因此问题是错误的。 你正在做一个只有1个元素的实体的笛卡尔,所以它是一个笛卡儿,但它不会乘以你的值

答案 1 :(得分:1)

不是使用旧的连接语法(没有连接条件 - 这是Toad警告的内容),您可以使用(ANSI / ISO)SQL-92连接语法并明确声明连接是{{1} }:

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; 不会期望连接条件(所以希望Toad会不必要地抱怨)。

稍微高效的版本(但由于涉及的行数不多,因此很少)将使用:

CROSS JOIN

然后Oracle可以在第一行之后停止从表中读取,而不必执行SELECT version FROM PRODUCT_COMPONENT_VERSION WHERE ROWNUM = 1 操作。

答案 2 :(得分:1)

在我的机器上(具有免费XE版Oracle的笔记本电脑 - 可能是最简单的安排),表PRODUCT_COMPONENT_VERSION有四行,而不是一行。有不同产品的版本,包括Oracle数据库和PL / SQL。在我的机器上,所有四行的版本都是相同的,但我不明白为什么一般应该这样做。

如果它们可能不同,首先你可以忽略告诉你交叉连接不是问题的所有答案,因为你只返回一行。你没有;你可能会返回多行。 SECOND,在您的查询中,为什么要从PRODUCT_COMPONENT_VERSION的所有行返回版本,而不仅仅是Oracle数据库的版本?我想像

这样的东西
WHERE PRODUCT LIKE 'Oracle%'

应该可以工作 - 并且您在SELECT子句中不需要DISTINCT。祝你好运!