Reputation: 153
We have inherited a set of tables from a third-party product. One of the tables has 2 foreign key constraints that link to the same column on the parent table. I have simplified the tables to demonstrate this:
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
);
Consequently when joining the 2 tables there is an OR condition as it needs to identify matching records on either column:
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;
Are there are any consequences of using OR in the JOIN or is there a 'better' way of doing it?
Thanks.
Upvotes: 3
Views: 196
Reputation: 116
Just in case you select to use the UNION ALL
alternative suggested, be aware of the fact that any records with orig_print_id = new_print_id
will apear twice in the results.
Upvotes: 0
Reputation: 1269623
The best approach is usually two left join
s:
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;
This puts the columns from the two profiles in a single row. The query can make full use of indexes. You don't specify what you want the results to look like. If you want only one value from the two joins, then use COALESCE()
.
Upvotes: 2
Reputation: 40481
An alternative will be to use UNION
or UNION ALL
which might have better execution plan :
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;
The consequences
is that or
is usually slower because the compiler can no longer perform an index seek. Other then that, it's ok .
Upvotes: 3