I'm trying to use a LEFT JOIN
to pull information into one table from two others. It works for most instances because each table has at most one match per row of the primary table. However, in some instances the third table has more than one match but the data column from that table is the same for each match.
A GROUP BY
at the end removes the duplicates; but is there a smarter way of somehow adding something to the join with table t3 to limit it to 1 row?
Thank you.
create table t1 (doc_id, track_id, timestamp);
create table t2 (doc_id, timestamp, starttime);
create table t3 (track_id, chapter, title);
insert into t1
values (1, '05009', 173), (2, '07290', 174), (3, '08002', 175);
insert into t2
values (1, 173, '02:05'), (2, 174, '05:17'), (3, 175, '10:35');
insert into t3
values ('08002', 1, 'title 08002'), ('05009', 2, 'title 05009'),('05009', 3, 'title 05009');
select
t1.*, t2.starttime, t3.title
from
t1
left join
t2 on (t1.doc_id,t1.timestamp) = (t2.doc_id,t2.timestamp)
left join
t3 on t1.track_id = t3.track_id;
/*
doc_id track_id timestamp starttime title
------ -------- --------- --------- -----------
1 05009 173 02:05 title 05009
1 05009 173 02:05 title 05009
2 07290 174 05:17 NULL
3 08002 175 10:35 title 08002
*/
select
t1.*, t2.starttime, t3.title
from
t1
left join
t2 on (t1.doc_id,t1.timestamp) = (t2.doc_id,t2.timestamp)
left join
t3 on t1.track_id = t3.track_id
group by
t1.track_id;
/*
doc_id track_id timestamp starttime title
------ -------- --------- --------- -----------
1 05009 173 02:05 title 05009
2 07290 174 05:17 NULL
3 08002 175 10:35 title 08002
*/
I'm trying to use a LEFT JOIN
to pull information into one table from two others. It works for most instances because each table has at most one match per row of the primary table. However, in some instances the third table has more than one match but the data column from that table is the same for each match.
A GROUP BY
at the end removes the duplicates; but is there a smarter way of somehow adding something to the join with table t3 to limit it to 1 row?
Thank you.
create table t1 (doc_id, track_id, timestamp);
create table t2 (doc_id, timestamp, starttime);
create table t3 (track_id, chapter, title);
insert into t1
values (1, '05009', 173), (2, '07290', 174), (3, '08002', 175);
insert into t2
values (1, 173, '02:05'), (2, 174, '05:17'), (3, 175, '10:35');
insert into t3
values ('08002', 1, 'title 08002'), ('05009', 2, 'title 05009'),('05009', 3, 'title 05009');
select
t1.*, t2.starttime, t3.title
from
t1
left join
t2 on (t1.doc_id,t1.timestamp) = (t2.doc_id,t2.timestamp)
left join
t3 on t1.track_id = t3.track_id;
/*
doc_id track_id timestamp starttime title
------ -------- --------- --------- -----------
1 05009 173 02:05 title 05009
1 05009 173 02:05 title 05009
2 07290 174 05:17 NULL
3 08002 175 10:35 title 08002
*/
select
t1.*, t2.starttime, t3.title
from
t1
left join
t2 on (t1.doc_id,t1.timestamp) = (t2.doc_id,t2.timestamp)
left join
t3 on t1.track_id = t3.track_id
group by
t1.track_id;
/*
doc_id track_id timestamp starttime title
------ -------- --------- --------- -----------
1 05009 173 02:05 title 05009
2 07290 174 05:17 NULL
3 08002 175 10:35 title 08002
*/
Share
Improve this question
edited Feb 18 at 5:11
marc_s
755k184 gold badges1.4k silver badges1.5k bronze badges
asked Feb 17 at 23:07
GaryGary
2,8712 gold badges17 silver badges41 bronze badges
2 Answers
Reset to default 1Don't join with t3
, join with a subquery that gets the unique values you care about. So change
left join t3
to
left join (
SELECT DISTINCT track_id, title
FROM t3
) AS t3
If the title is always the same regardless of the chapter, this also suggests that your database is not properly normalized. t3
should be split into two tables:
CREATE TABLE t3a (track_id, title, PRIMARY KEY (track_id));
CREATE TABLE t3b (track_id, chapter,
PRIMARY KEY (track_id, chapter),
FOREIGN KEY (track_id) REFERENCES t3a (track_id));
Then you would just join with t3a
to get your desired result.
After some additional thought, a CTE might be a good approach; because, even though a multiple-table join may look concise, the joins appear to still be happening in steps; and it appears that this CTE selects the distinct only from among those that match rather than selecitng distinct from all of t3 to start.
with
t1j3 as
(
select
distinct t3.track_id, t3.title
from
t3
inner join
t1
on
t3.track_id = t1.track_id
)
select
t1.*, t2.starttime, t1j3.title
from
t1
left join
t2
on
(t1.doc_id,t1.timestamp) = (t2.doc_id,t2.timestamp)
left join
t1j3
on
t1.track_id = t1j3.track_id
;
/*
doc_id track_id timestamp starttime title
------ -------- --------- --------- -----------
1 05009 173 02:05 title 05009
2 07290 174 05:17 NULL
3 08002 175 10:35 title 08002
*/