【问题标题】:OR Condition in Oracle SQLOracle SQL 中的 OR 条件
【发布时间】:2018-10-08 12:22:09
【问题描述】:

我们从第三方产品继承了一组表。其中一张表有 2 个外键约束,它们链接到父表上的同一列。我已经简化了表格来证明这一点:

CREATE TABLE profile_defn 
(   
  profile_id NUMBER(10,0), 
  profile_name  VARCHAR2(50),
  CONSTRAINT pk1 PRIMARY KEY (profile_id)
);

CREATE TABLE letter_defn 
(
  letter_defn_id  NUMBER(10,0), 
  letter_name     VARCHAR2(50 BYTE), 
  orig_print_id   NUMBER(10,0),
  new_print_id    NUMBER(10,0),
  CONSTRAINT fk1 FOREIGN KEY (orig_print_id) REFERENCES profile_defn (profile_id) ENABLE,
  CONSTRAINT fk2 FOREIGN KEY (new_print_id) REFERENCES profile_defn (profile_id) ENABLE
);

INSERT INTO profile_defn
VALUES
(
  1,
  'profile1'
);

INSERT INTO profile_defn
VALUES
(
  2,
  'profile2'
);

INSERT INTO profile_defn
VALUES
(
  3,
  'profile3'
);

INSERT INTO letter_defn
VALUES 
(
  1,
  'letter1',
  1,
  2
);

INSERT INTO letter_defn
VALUES 
(
  1,
  'letter2',
  2,
  3
);

因此,当连接 2 个表时,需要使用 OR 条件来识别任一列上的匹配记录:

SELECT * FROM letter_defn ld
JOIN profile_defn p 
ON ld.orig_print_id = p.profile_id OR ld.new_print_id = p.profile_id;

在 JOIN 中使用 OR 是否有任何后果,或者是否有“更好”的方法?

谢谢。

【问题讨论】:

    标签: sql oracle join inner-join


    【解决方案1】:

    另一种方法是使用UNIONUNION ALL,这可能有更好的执行计划:

    SELECT * FROM letter_defn ld 
    JOIN profile_defn p ON ld.orig_print_id = p.profile_id 
    UNION
    SELECT * FROM letter_defn ld 
    JOIN profile_defn p ON ld.new_print_id = p.profile_id;
    

    consequencesor 通常较慢,因为编译器无法再执行索引查找。除此之外,没关系。

    【讨论】:

    • 无论如何,Oracle 很可能会将 join-with-or 转换为单独的联合查询。
    • 确实,这就是我说“可能”的原因:)
    • 是的,我只是想让 OP 知道优化器很可能会按照您的建议进行操作。如果您想将其作为 OP 的额外信息将其移至您的答案中,我很高兴删除我的 cmets。 *{:-)
    【解决方案2】:

    最好的办法通常是两个left joins:

    SELECT ld.*, . . .
    FROM letter_defn ld LEFT JOIN
         profile_defn po
         ON ld.orig_print_id = po.profile_id LEFT JOIN
         profile_defn pn
         ON ld.new_print_id = p.profile_id 
    WHERE po.profile_id IS NOT NULL OR pn.profile_id IS NOT NULL;
    

    这会将两个配置文件中的列放在一行中。查询可以充分利用索引。你没有指定你想要的结果是什么样的。如果您只需要两个连接中的一个值,请使用COALESCE()

    【讨论】:

    • 你不需要LEFT JOIN - 一个简单的INNER JOIN 更好,因为存在已经由外键约束保证 - 如果 orig_print_id 和 new_print_id 不为空,那就是......
    • @Radagast81 DDL 说 FK 可以为空。第一个内部连接可能会删除 profile_id。该 profile_id 将无法在第二个内部连接中匹配。
    【解决方案3】:

    万一您选择使用建议的 UNION ALL 替代方案,请注意任何带有orig_print_id = new_print_id 的记录都会在结果中出现两次。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2015-08-08
      • 2016-03-15
      • 2016-12-20
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多