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

Sql 将一个表多次连接到其他表,sql,Sql,我有三张桌子: 表用户(userid用户名) 表键(userid keyid) 桌上型笔记本电脑(用户ID LAPTOID) 我想要所有拥有钥匙或笔记本电脑的用户,或者两者都有。如何编写查询,以便它使用表用户和表键之间的连接,以及表用户和表键之间的连接 主要问题是,在实际场景中,大约有12个表联接,类似于: “从左连接中选择..,在(…)上选择b,在(…)上选择c,在(…)上选择d,在(…)上选择e,f,g,其中…” 我看到a可以连接到b,a也可以连接到f。因此,假设我不能使表a、b和f并排出现

我有三张桌子:

表用户(userid用户名)

表键(userid keyid)

桌上型笔记本电脑(用户ID LAPTOID)

我想要所有拥有钥匙或笔记本电脑的用户,或者两者都有。如何编写查询,以便它使用表用户和表键之间的连接,以及表用户和表键之间的连接

主要问题是,在实际场景中,大约有12个表联接,类似于:

“从左连接中选择..,在(…)上选择b,在(…)上选择c,在(…)上选择d,在(…)上选择e,f,g,其中…”

我看到a可以连接到b,a也可以连接到f。因此,假设我不能使表a、b和f并排出现,那么如何编写sql查询呢

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
编辑 “主要问题是,在实际场景中,大约有12个表联接,类似于: “选择..”。。从(…)上的左连接b,从(…)上的左连接d,从(…)上的左连接e,f,g,其中, 我看到a可以连接到b,a也可以连接到f。所以假设我不能使表a、b和f并排出现,我该如何编写sql查询?”

可以根据需要使用任意数量的左侧外部联接。使用主键将表连接到其他表或任何其他字段,其中一个表的字段值应与其他表的字段值匹配

用英语比用语言解释得好

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

依此类推

您可以使用多个联接来组合多个表:

select *
from user u
left join key k on u.userid = k.userid
left join laptop l on l.userid = u.userid
“左连接”还可以查找没有钥匙或笔记本电脑的用户。如果将两者都替换为“内部连接”,则只会找到拥有笔记本电脑和密钥的用户

当“左联接”找不到行时,它将在其字段中返回NULL。因此,您可以选择所有拥有笔记本电脑或钥匙的用户,如下所示:

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是特殊的,因为您将其比较为“field is not NULL”而不是“field NULL”

在您的评论后添加:假设您有一个桌面鼠标,它与笔记本电脑相关,但与用户无关。您可以像这样加入:

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

如果这不能回答你的问题,你必须进一步澄清。

正如你所描述的那样,你只想知道某人是否有笔记本电脑或钥匙。我将使用子查询而不是联接编写查询:

select * 
from user 
where userid in (select userid from key union select userid from laptop)
原因是,通过join,拥有多台笔记本电脑或多把钥匙的人将被多次列出(除非您使用
distinct
)。即使使用
distinct
,最终也会得到效率较低的查询(至少在Oracle上,查询优化器似乎无法创建有效的计划)

[编辑以更正Rashmi Pandit指出的内容。]

解决方案一:

 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
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

[...]
解决方案二:

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 [...]

只是一个猜测,你也可以查看这两个的执行计划,看看UNION one是否更重,反之亦然。

每个用户都必须有钥匙或笔记本电脑。对吗?你可能是对的,也可能是错的,但是你完全不在乎!不过仍然很有趣:)Q1:你想只知道用户(userid)还是还想知道他们到底有什么?问题2:一个用户是否可以拥有一种类型的多个项目(2台笔记本电脑或3把钥匙)?我认为最后一个u.userid应该是k.userid,抱歉之前没有澄清这个问题:我已经为这个问题添加了更多细节,所以你的回答似乎无法解决我的问题。如果你指定左外连接,它将不会是交叉连接。左外部联接比子查询快。我在Oracle数据库中快速试用了它:没错,它不会导致交叉联接。但是它也不比子查询方法快——实际上慢了两倍多。除了添加更多的JOIN和ON子句之外,我只想对查询做很少的修改,所以现在我正在寻找一种不使用子查询的方法。我也有mysql数据库,它的行为可能不同于oracles在嵌套查询上的行为我不确定abt Oracle,但我总的来说听说连接比子查询快。。。可能对于大量的数据来说,这是非常有用的,因为SQL n00b完全符合我的要求,而且引导时可读性很强。我完成了这个问题,以表明我的主要困难是无法使三个表并排显示,例如完整的表联接(我的意思是:“从c,d”等)在第一个答案中,您仍然缺少where子句,如“where k.userid不为null或l.userid不为null”,该子句用于过滤没有任何内容的用户。
-- // 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