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