避免笛卡尔查询 - 找到合适的 "where clause"

Avoid cartesian queries - find a proper "where clause"

以下代码生成更改密码语句以更改 Oracle 数据库中的所有标准密码。在版本 12.1.0.2.0 中,无法再将其更改为无效的密码值。这就是为什么我必须构建这个 switch case 结构的原因。 Toad 在末尾对连接构造发出警告(规则 5807)。它说“避免笛卡尔查询——使用 where 子句……”。关于适用于所有 Oracle 数据库版本的“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

Toad 只是警告您正在执行没有 JOIN 条件的连接。 在这种情况下,您确实在这样做,但是所涉及的实体之一(来自 PRODUCT_COMPONENT_VERSION 的查询)应该 return 只有一个值,因此问题是错误的。 你正在用一个只有 1 个元素的实体做一个笛卡尔坐标,所以它是一个笛卡尔坐标,但它不会乘以你的值

如果你需要用户和产品组件的所有组合,笛卡尔积是正确的选择。留意可能写入文件的行数(用户 * 组件版本)。您可能需要某种批处理。

您可以使用 (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;

因为第二个 table 连接只会 return 一行,所以你不会增加行数 returned 并且 CROSS JOIN 不期望连接条件(所以希望蟾蜍会停止不必要的抱怨)。

一个稍微更有效的版本(但它是最小的,因为涉及的行不多)将使用:

SELECT version FROM PRODUCT_COMPONENT_VERSION WHERE ROWNUM = 1

然后Oracle可以停止从第一行之后的table读取,而不必执行DISTINCT操作。

在我的机器上(带有免费 XE 版 Oracle 的膝上型电脑 - 可能的最简单排列)table PRODUCT_COMPONENT_VERSION 有四行,没有一行。有不同产品的版本,包括 Oracle 数据库和 PL/SQL。在我的机器上,版本在所有四行中都是相同的,但我不明白为什么通常会出现这种情况。

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

WHERE PRODUCT LIKE 'Oracle%'

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