简体   繁体   English

将一个表多次连接到其他表

[英]joining one table multiple times to other tables

I have three tables: 我有三张桌子:

Table User( userid username) 表用户(userid用户名)

Table Key( userid keyid) 表键(userid keyid)

Table Laptop( userid laptopid) 表笔记本电脑(userid laptopid)

i want all users who have either a key or a laptop, or both. 我想要所有拥有钥匙或笔记本电脑或两者兼而有之的用户。 How do i write the query so that it uses a join between table User and table Key, as well as a join between table User and table Laptop? 我如何编写查询,以便它使用表User和表Key之间的连接,以及表User和表Laptop之间的连接?

The main problem is that in the actual scenario, there are twelve or so table joins, sth like: 主要问题是在实际场景中,有十二个左右的表连接,如:

" select .. From a left join b on (...), c join d on (..),e,f,g where ...", “选择..从左边的连接b开始(...),c连接d on(..),e,f,g where ...”,

and i see that a could be joined to b, and a could also be joined to f. 我看到a可以加入b,a也可以加入f。 So assuming i can't make the tables a,b, and f appear side-by-side, how do i write the sql query? 所以假设我不能使表a,b和f并排出现,我该如何编写sql查询?

You can use multiple joins to combine multiple tables: 您可以使用多个联接来组合多个表:

select *
from user u
left join key k on u.userid = k.userid
left join laptop l on l.userid = u.userid

A "left join" also finds users which do not have a key or a laptop. “左连接”还可以找到没有密钥或笔记本电脑的用户。 If you replace both with "inner join", it would find only users with a laptop and a key. 如果用“内部连接”替换它们,它将只找到有笔记本电脑和密钥的用户。

When a "left join" does not find a row, it will return NULL in its fields. 当“左连接”找不到行时,它将在其字段中返回NULL。 So you can select all users that have either a laptop or a key like this: 因此,您可以选择所有拥有笔记本电脑或密钥的用户:

select *
from user u
left join key k on u.userid = k.userid
left join laptop l on l.userid = u.userid
where k.userid is not null or l.userid is not null

NULL is special, in that you compare it like "field is not null" instead of "field <> null". NULL是特殊的,因为你比较它像“field is not null”而不是“field <> null”。

Added after your comment: say you have a table Mouse, that is related to Laptop, but not to User. 在你的评论后添加:说你有一个表鼠标,它与笔记本电脑有关,但与用户有关。 You can join that like: 您可以加入以下内容:

select *
from user u
left join laptop l on l.userid = u.userid
left join mouse m on m.laptopid = l.laptopid

If this does not answer your question, you gotta clarify it some more. 如果这不能回答你的问题,你需要澄清一些。

-- // Assuming that a user can have at max 1 items of each type
SELECT      u.*
-- // Assuming that a user can have more then 1 items of each type, just add DISTINCT:
-- // SELECT      DISTINCT u.*
FROM        "User" u
LEFT JOIN   "Key"    u1 ON u.UserID = u1.UserID
LEFT JOIN   "Laptop" u2 ON u.UserID = u2.UserID
LEFT JOIN   "Server" u3 ON u.UserID = u3.UserID
-- // ...
WHERE       COALESCE(u1.UserID, u2.UserID, u3.UserID /*,...*/) IS NOT NULL
select distinct u.userid, u.username
from User u 
    left outer join Key     /* k on u.userid = k.userid */
    left outer join Laptop  /* l on u.userid = l.userid */
where k.userid is not null or l.userid is not null

EDIT "The main problem is that in the actual scenario, there are twelve or so table joins, sth like: " select .. From a left join b on (...), c join d on (..),e,f,g where ...", and i see that a could be joined to b, and a could also be joined to f. So assuming i can't make the tables a,b, and f appear side-by-side, how do i write the sql query?" 编辑 “主要问题是,在实际场景中,有十二个左右的表连接,如:”选择..从左边的连接b上(...),c连接d(...),e, f,g where ...“,我看到a可以连接到b,a也可以连接到f。所以假设我不能使表a,b和f并排出现,我该如何编写sql查询?“

You can have as many left outer joins as required. 您可以根据需要拥有尽可能多的左外连接。 Join the table with the primary key to the rest of the tables or on any other field where field values of one table should match field values of other table. 使用主键将表连接到其余表或任何其他字段,其中一个表的字段值应与其他表的字段值匹配。

eg will explain better than words 例如,将比文字更好地解释

select * 
from a
 left outer join b on a.pk = b.fk -- a pk should match b fk
 left outer join c on a.pk = c.fk -- a pk should match c fk
 left outer join d on c.pk = d.fk -- c pk should match d fk

and so on 等等

As you described the case, you only wanted to know if someone has a laptop or a key. 正如您所描述的那样,您只想知道某人是否有笔记本电脑或钥匙。 I would write the query with a subquery rather than a join: 我会用子查询而不是连接来编写查询:

select * 
from user 
where userid in (select userid from key union select userid from laptop)

The reason for this is that by a join a person with multiple laptops or multiple keys will be listed several times (unless you use distinct ). 这样做的原因是,通过连接,具有多个笔记本电脑或多个键的人将被列出多次(除非您使用distinct )。 And even you use distinct you end up with a less efficient query (at least on Oracle the query optimizer doesn't appear to be able to create an efficient plan). 即使您使用distinct最终查询效率较低(至少在Oracle上,查询优化器似乎无法创建有效的计划)。

[Edited to correct what Rashmi Pandit pointed out.] [编辑纠正Rashmi Pandit指出的内容。]

Solution one: 解决方案一:

SELECT * FROM [User] u
INNER JOIN [Key] k
ON u.userid = k.userid

UNION

SELECT * FROM [User] u
INNER JOIN Laptop l
ON u.userid = l.userid

[...]

Solution two: 解决方案二:

SELECT * FROM [User] u
LEFT JOIN [Key] k
ON u.userid = k.userid
LEFT JOIN Laptop l
ON u.userid = l.userid
LEFT JOIN [...]
WHERE k.userid IS NOT NULL
OR l.userid IS NOT NULL
OR [...]

Just a guess, also you could check the execution plan for theses two to see if the UNION one is heavier or vice versa. 只是一个猜测,你也可以检查这两个的执行计划,看看UNION一个是否更重,反之亦然。

 SELECT * 
 FROM User
 LEFT JOIN Key ON User.id = Key.user_id
 LEFT JOIN Laptop ON User.id = Laptop.user_id
 WHERE Key.id IS NOT NULL OR Laptop.id IS NOT NULL

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM