我在Postgres中运行以下查询:
SELECT raw_times.*, efforts.id as effort_id, efforts.event_id as event_id, splits.id as split_id
FROM raw_times
INNER JOIN event_groups ON event_groups.id = raw_times.event_group_id
INNER JOIN events ON events.event_group_id = event_groups.id
INNER JOIN efforts ON efforts.event_id = events.id
INNER JOIN aid_stations ON aid_stations.event_id = events.id
INNER JOIN splits ON splits.id = aid_stations.split_id
WHERE efforts.bib_number::text = raw_times.bib_number
AND splits.parameterized_base_name = raw_times.parameterized_split_name
这个想法是找到匹配的号码和拆分名称,并返回填充了各种关系id的raw_time记录。
用简单的英语,逻辑的工作原理如下:对于每个raw_time,检查event_group_id。 event_group有很多事件,事件有很多工作,而努力表有一个bib_number列。 Bib编号在event_group中是唯一的,但在整个工作表中并不是唯一的。
因此,对于每个raw_time,因为我们知道event_group_id和bib_number,我们可以确定它与哪个工作有关。知道了这些努力,我们也可以知道事件(因为努力有一个event_id)。
事件通过aid_stations连接表进行了多次拆分。拆分名称在事件中是唯一的。因为我们知道事件(如上所述确定)并且我们知道拆分名称(它是raw_times表上的列),所以我们可以确定split_id。
对于存在匹配的号码和拆分名称的记录,查询按预期工作。但是对于bib编号或拆分名称不匹配的记录,不满足WHERE子句,因此根本不返回raw_time记录。
我尝试使用LEFT JOIN代替每个INNER JOIN进行查询,但我得到的结果相同。
我想要的是返回所有raw_time记录,但如果没有匹配的拆分名称,则返回split_id为NULL的记录,如果没有匹配的bib编号,则返回记录对于effort_id,event_id和split_id,为NULL。
raw_times表如下所示:
id event_group_id parameterized_split_name bib_number
3 53 finish 11
4 53 finish 603
5 53 finish 9999
6 53 nonexistent 603
event_groups表如下所示:
id
53
51
事件表如下所示:
id event_group_id
26 53
28 53
18 51
努力表如下所示:
id event_id bib_number
22183 26 11
22400 28 603
5747 18 11
aid_stations表如下所示:
id event_id split_id
236 26 30
237 26 31
238 26 106
239 26 111
240 26 112
241 26 109
242 26 113
254 28 119
255 28 118
138 18 1
150 18 16
拆分表如下所示:
id parameterized_base_name
30 finish
31 start
106 aid-1
109 aid-4
111 aid-2
112 aid-3
113 aid-5
118 start
119 finish
1 start
16 finish
查询应该返回:
id event_group_id parameterized_split_name bib_number effort_id event_id split_id
3 53 finish 11 22183 26 30
4 53 finish 603 22400 28 119
6 53 nonexistent 603 22400 28 NULL
5 53 finish 9999 NULL NULL NULL
这是指向ERD的链接:https://github.com/SplitTime/OpenSplitTime/blob/master/erd.pdf
答案 0 :(得分:2)
通过拥有样本数据和想要的结果的优势,“缺失元素”似乎需要通过split_id的相关子查询来获得有限的结果。
的PostgreSQL 9.6中查看此内容CREATE TABLE raw_times
(id int, event_group_id int, parameterized_split_name varchar(11), bib_number int)
;
INSERT INTO raw_times
(id, event_group_id, parameterized_split_name, bib_number)
VALUES
(3, 53, 'finish', 11),
(4, 53, 'finish', 603),
(5, 53, 'finish', 9999),
(6, 53, 'nonexistent', 603)
;
CREATE TABLE event_groups
(id int)
;
INSERT INTO event_groups
(id)
VALUES
(53)
;
CREATE TABLE efforts
(id int, event_id int, bib_number int)
;
INSERT INTO efforts
(id, event_id, bib_number)
VALUES
(22183, 26, 11),
(22400, 28, 603)
;
CREATE TABLE aid_stations
(id int, event_id int, split_id int)
;
INSERT INTO aid_stations
(id, event_id, split_id)
VALUES
(236, 26, 30),
(237, 26, 31),
(238, 26, 106),
(239, 26, 111),
(240, 26, 112),
(241, 26, 109),
(242, 26, 113),
(254, 28, 119),
(255, 28, 118)
;
CREATE TABLE splits
(id int, parameterized_base_name varchar(6))
;
INSERT INTO splits
(id, parameterized_base_name)
VALUES
(30, 'finish'),
(31, 'start'),
(106, 'aid-1'),
(109, 'aid-4'),
(111, 'aid-2'),
(112, 'aid-3'),
(113, 'aid-5'),
(118, 'start'),
(119, 'finish')
;
查询1 :
select
r.id, r.event_group_id, r.parameterized_split_name, r.bib_number
, e.id as effort_id
, e.event_id
, s.split_id
from raw_times r
left join (
select ef.id, ef.event_id, ef.bib_number, ev.event_group_id
from efforts ef
inner join events ev on ef.event_id = ev.id
) e on r.bib_number = e.bib_number
and e.event_group_id = r.event_group_id
left join lateral (
select a.split_id from aid_stations a
inner join splits s on a.split_id = s.id
where a.event_id = e.event_id
and s.parameterized_base_name = r.parameterized_split_name
limit 1) s on true
order by r.bib_number, r.id
;
<强>结果:
| id | event_group_id | parameterized_split_name | bib_number | effort_id | event_id | split_id |
|----|----------------|--------------------------|------------|-----------|----------|----------|
| 3 | 53 | finish | 11 | 22183 | 26 | 30 |
| 4 | 53 | finish | 603 | 22400 | 28 | 119 |
| 6 | 53 | nonexistent | 603 | 22400 | 28 | (null) |
| 5 | 53 | finish | 9999 | (null) | (null) | (null) |
请注意。如果使用较旧版本的Postgres,则可以在select子句中使用相关子查询来代替上面看到的left join lateral
。
答案 1 :(得分:0)
在这种情况下,请在执行LEFT OUTER连接时添加条件。
SELECT raw_times.*, efforts.id as effort_id, efforts.event_id as event_id, splits.id as split_id
FROM raw_times
INNER JOIN event_groups ON event_groups.id = raw_times.event_group_id
INNER JOIN events ON events.event_group_id = event_groups.id
LEFT JOIN efforts ON efforts.event_id = events.id AND efforts.bib_number::text = raw_times.bib_number
INNER JOIN aid_stations ON aid_stations.event_id = events.id
LEFT JOIN splits ON splits.id = aid_stations.split_id AND splits.parameterized_base_name = raw_times.parameterized_split_name
编辑:
SELECT raw_times.*, efforts.id as effort_id, efforts.event_id as event_id, splits.id as split_id
FROM raw_times
INNER JOIN event_groups ON event_groups.id = raw_times.event_group_id
INNER JOIN events ON events.event_group_id = event_groups.id
LEFT JOIN efforts ON efforts.event_id = events.id
INNER JOIN aid_stations ON aid_stations.event_id = events.id
LEFT JOIN splits ON splits.id = aid_stations.split_id
WHERE (efforts.bib_number::text = raw_times.bib_number OR efforts.event_id IS NULL)
AND (splits.parameterized_base_name = raw_times.parameterized_split_name OR splits.id IS NULL)