我有五个表,让我们称它们为A到E,每个表都有一个唯一的密钥和一个外键,它是parent
表的唯一键。
因此:A-> B-> C-> D-> E
A包含字段A_key
和B_key
; B有键B_key
和C_key
,依此类推......
鉴于A_key
,我该如何SELECT * from E
?这让我难过:-(
我需要嵌套的JOIN,还是什么?
为什么系统不让我提交问题而不在最后加上这个?为什么说它包含不正确的语法?
[更新]
我刚刚意识到我的说错了。
它是A->B->C->D<-E
- 所有内容都指向“向下”,直到最后一个指向“向上”。
我看不出如何更改数据库。有没有办法调整@GiorgosBetsos的答案?
根据评论中的要求,以下是表格。鉴于campaign_id,我想SELECT * FROM taps
mysql> describe campaigns;
+--------------+------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+--------------+------------+------+-----+---------+----------------+
| campaign_id | int(11) | NO | PRI | NULL | auto_increment |
| title | text | NO | | NULL | |
| description | text | YES | | NULL | |
| path_to_logo | text | YES | | NULL | |
| start_time | text | NO | | NULL | |
| end_time | text | NO | | NULL | |
| paused | tinyint(1) | NO | | 0 | |
+--------------+------------+------+-----+---------+----------------+
7 rows in set (0.00 sec)
mysql> describe destinations;
+----------------+---------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+----------------+---------------+------+-----+---------+----------------+
| destination_id | int(11) | NO | PRI | NULL | auto_increment |
| campaign_id | int(11) | NO | PRI | NULL | |
| url | varchar(2048) | NO | | NULL | |
| description | varchar(2048) | NO | | NULL | |
+----------------+---------------+------+-----+---------+----------------+
4 rows in set (0.00 sec)
mysql> describe connections;
+----------------+---------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+----------------+---------+------+-----+---------+----------------+
| connection_id | int(11) | NO | MUL | NULL | auto_increment |
| destination_id | int(11) | NO | | NULL | |
| description | text | NO | | NULL | |
| tag_id | int(11) | YES | | NULL | |
| country | text | YES | | NULL | |
| county | text | YES | | NULL | |
| town | text | YES | | NULL | |
| post_code | text | YES | | NULL | |
| custom | text | YES | | NULL | |
+----------------+---------+------+-----+---------+----------------+
9 rows in set (0.00 sec)
mysql> describe tags;
+---------------+---------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+---------------+---------+------+-----+---------+-------+
| tag_id | int(11) | NO | PRI | NULL | |
| tag_type | int(11) | NO | | NULL | |
| customer_id | int(11) | NO | PRI | NULL | |
| connection_id | int(11) | NO | PRI | NULL | |
+---------------+---------+------+-----+---------+-------+
4 rows in set (0.00 sec)
mysql> describe taps;
+-------------+-----------+------+-----+-------------------+-------+
| Field | Type | Null | Key | Default | Extra |
+-------------+-----------+------+-----+-------------------+-------+
| tag_id | int(11) | NO | | NULL | |
| time_stamp | timestamp | NO | | CURRENT_TIMESTAMP | |
| device_id | text | YES | | NULL | |
| device_type | text | YES | | NULL | |
+-------------+-----------+------+-----+-------------------+-------+
4 rows in set (0.00 sec)
答案 0 :(得分:1)
这应该适合你:
SELECT *
FROM E
WHERE EXISTS (
SELECT 1
FROM A
JOIN B ON A.B_key = B.B_key
JOIN C ON B.C_key = C.C_key
JOIN D ON C.D_key = D.D_key
WHERE D.E_key = E.E_key AND A.A_key = ? )
答案 1 :(得分:1)
以下查询将允许您选择taps
表中的所有列:
SELECT
taps.tag_id,
taps.time_stamp,
taps.device_id,
taps.device_type
FROM campaigns AS camp
INNER JOIN destinations AS dest
ON dest.campaign_id = camp.campaign_id
INNER JOIN connections AS conn
ON conn.destination_id = dest.destination_id
INNER JOIN tags
ON tags.connection_id = conn.connection_id
INNER JOIN taps
ON taps.tag_id = tags.tag_id
WHERE camp.campaign_id = :campaign_id
您可以使用SELECT
替换taps.*
之后的4行,但使用*
是不好的做法,就像您将来添加任何列一样,您将开始回归不同的结果。
此外,此查询应该比Giorgos提供的查询更有效,因为EXISTS
通常不会像JOIN
那样进行优化。
(我发誓,我没有跟着你,试着提出你的答案,Giorgos,我碰巧碰到了两个与你相同的问题,并认为我可以提供更好的解决方案。)
从你如何描述你所遇到的问题来看,这是一个&#34;深度嵌套的JOIN&#34;表明您正在查看数据库关系不正确,因为许多人(包括我自己)在数据库相对缺乏经验的情况下首先会这样做。
数据库将采用上面的INNER JOIN
列表,并决定一个开始。在这种情况下,它将从campaigns
表开始,因为它知道它可以从该表中获得最小的结果(一行,或者没有,如果没有与campaign_id
匹配。)
从那里开始,它将构建一行,并且对于destinations
表中的每个记录,它将找到所有具有匹配行ON
campaign_id
列的记录。从那里开始,它会将destination_id
添加到其结果中,对于匹配的destinations
表中的每一行,都会添加一个。
然后,对于其结果中的每一行(让我们说有3个目的地匹配),它会找到与其结果集中具有相同destination_id
的所有连接匹配。然后,对于每个给定的connection_id
,它会将destination_id
添加到其结果中,每个行对应于连接表中的每一行。让我们说3个目的地分别有0,1和4个连接。这意味着数据库现在将结果设置为5行(destination_id
没有任何connections
从结果中删除,因为我们正在使用INNER JOIN
s。)
该过程重复该行,直到它最终到达taps
表,并且该表中的所有信息都被添加到结果中。最后,它只从它所持有的信息中获取所需的列,并从taps
表中返回行。
重要的是,您没有告诉它要使用的订单。从数据库的角度来看,以下查询是等效的:
SELECT
taps.tag_id,
taps.time_stamp,
taps.device_id,
taps.device_type
FROM taps
INNER JOIN tags
ON taps.tag_id = tags.tag_id
INNER JOIN connections AS conn
ON tags.connection_id = conn.connection_id
INNER JOIN destinations AS dest
ON conn.destination_id = dest.destination_id
INNER JOIN campaigns AS camp
ON dest.campaign_id = camp.campaign_id
WHERE camp.campaign_id = :campaign_id
请注意,虽然从我们的角度来看订单是相反的,但数据库仍将按照与上述相同的顺序运行。这是因为数据库希望从最小的行集开始,然后一次向结果添加一个表。
您不必担心订单或任何嵌套。只担心通过ON
语句告诉数据库如何比较表。您甚至可以将表(在此示例中)放在您想要的几乎任何顺序中,只要任何ON
语句仅引用已定义的表(从我们的阅读角度,从上到下。)
我的第二个查询实际上可能更容易理解集合概念。从您想要的信息(taps
表)开始,作为FROM
子句。然后启动JOIN
表,使您更接近WHERE
子句中的信息,直到您为数据库引擎提供足够的信息,将事物拼凑在一起并获取所需的信息。
希望这有助于让你开始思考正确的道路(正如有人为我做的,大约5年前)。如果您有任何问题,请随时提出,我将使用这些来改进我的解释。