我不明白为什么在下面的查询中必须两次引用zones表(如zpu和zdo)。当我尝试用一个";区域";表,而不是把它分成zpu和zdo,我有不同的结果。结果表必须有两列,一列带有拾取位置,另一列带有放下位置。位置包含在";区域";桌子
我不明白为什么会这样,我在SQL机制方面缺少什么。
表格:
跳闸
tpep_pickup_datetime | tpep _dropoff_datetime[/th> |
|
---|---|---|
"2021-01-01 00:30:10"> | "2021-01-01 00:36:12"> | 11.8 |
"2021-01-01 00:51:20"> | "2021-01-01 00:52:19"> | 4.3 |
"2021-01-01 00:43:30"> | "2021-01-01 01:11:06"> | 51.95 |
"2021-01-01 00:15:48"> | "2021-01-01 00:31:01"> | 36.35 |
132 | ||
"2021-01-01 00:31:49"> | "2021-01-01 00:48:21"> | 24.36 |
"2021-01-01 00:16:29"> | "2021-01-01 00:24:30"> | 14.15 |
"2021-01-01 00:00:28"> | "2021-01-01 00:17:28"> | 17.3 |
"2021-01-01 00:12:29"> | "2021-01-01 00:30:34"> | 21.8 |
您选择了行程和联接地址,您想知道为什么您被迫再次联接这些地址,以及为什么只告诉DBMS一次以获取地址还不够。
这种误解可能是由你正在使用的古老的联接语法引起的——这种语法主要在20世纪80年代使用,直到1992年显式联接成为SQL标准。
当您联接表时,您实际上会联接表行。
使用select * from trips, zones
,您可以将每个行程行与每个区域行连接起来。有8个行程行和10个区域,您可以得到80个结果行。所以你每次旅行都加入了所有十个区域。使用select * from trips t, zones zpu, zones zdo
,您会得到800行的结果,每个行程与所有十个区域组合,这些区域再次与所有十种区域组合,即每次行程所有100种可能的区域组合。
在您的查询中,您有WHERE t.pulocationid = zpu.locationid AND t.dolocationid = zdo.locationid
。对于一个行程,其100个中间结果行中只有一个与该标准匹配,而其他99个被忽略。
现在,如果您只加入一次zones表,那么在您的中间结果中,每次旅行有十行,每行将包含一个zone。现在根据您的标准,有两个选项:使用AND
或OR
:
select * from trips t, zones z
where t."PULocationID" = z."LocationID" AND t."DOLocationID" = z."LocationID"
这只会选择t.pulocationid=t.dolocationid的行,因为条件要求它们都与连接行中的一个区域匹配。在您的样本数据中,没有一次旅行中两个位置相等。你会得到一个空的结果集。
select * from trips t, zones z
where t."PULocationID" = z."LocationID" OR t."DOLocationID" = z."LocationID"
通过此查询,您将获得区域与t.pulocationid匹配的行和区域与t.dolocationid相匹配的行。也就是说,每次旅行将获得两个结果行,一个与接送区域,一个具有还车区域。
但您希望每次旅行都有一个结果行,两个区域都在同一结果行中。
显式联接使其可读性更强:
select
tpep_pickup_datetime,
tpep_dropoff_datetime,
total_amount,
CONCAT(zpu."Borough", ' / ', zpu."Zone") AS "pick_up_loc",
CONCAT(zdo."Borough", ' / ', zpu."Zone") AS "drop_off_loc"
from trips t
inner join zones zpu on zpu."LocationID" = t."PULocationID"
inner join zones zdo on zdo."LocationID" = t."DOLocationID";
这与查询的作用完全相同,但更易于阅读。来一次旅行,加入取车地点行,加入还车地点行。