问题描述
我需要连接3个表,这些表之间没有关系,除了它们都有共同的字段(profiledid和instanceid) 例如,这3个表分别是成就[0条记录],附件[6条记录]和大学学习[4条记录]
如果我使用内部联接,它将执行笛卡尔积,我将获得24条记录,
SELECT a.*,v.*,c.* FROM dbo.Profile p
LEFT JOIN Achievement v ON p.id = v.ProfileId AND v.InstanceId = 6559
LEFT JOIN Attachment a ON p.id = a.ProfileId AND a.InstanceId = 6559
LEFT JOIN CollegeAttended c ON p.id = c.ProfileId AND c.InstanceId = 6559
WHERE p.Id = 5574443
但是,我只需要获得6条记录即可。
我写了这个查询,得到了6条记录。但是,如果驱动表(在此查询附件中)具有最大的行数,则此查询将运行良好。
SELECT t1.*,t2.*,t3.*
FROM (SELECT a.*,ROW_NUMBER() OVER (ORDER BY id) AS rn
FROM Attachment a
WHERE a.ProfileId = 5574443 AND a.InstanceId = 6559) AS t1
LEFT OUTER JOIN (
SELECT b.*,ROW_NUMBER() OVER (ORDER BY id) AS rn
FROM Achievement b
WHERE b.ProfileId = 5574443 AND b.InstanceId = 6559) AS t2 ON t1.rn = t2.rn
LEFT OUTER JOIN (
SELECT c.*,ROW_NUMBER() OVER (ORDER BY id) AS rn
FROM CollegeAttended c
WHERE c.ProfileId = 5574443 AND c.InstanceId = 6559) AS t3 ON t1.rn = t3.rn
如果附件有0条记录,则此查询将不返回任何记录。
谢谢
解决方法
描述问题时,可以使用full outer join
:
SELECT t1.*,t2.*,t3.*
FROM (SELECT a.*,ROW_NUMBER() OVER (ORDER BY id) AS rn
FROM Attachment a
WHERE a.ProfileId = 5574443 AND a.InstanceId = 6559
) t1 FULL JOIN
(SELECT b.*,ROW_NUMBER() OVER (ORDER BY id) AS rn
FROM Achievement b
WHERE b.ProfileId = 5574443 AND b.InstanceId = 6559
) t2
USING (rn) FULL JOIN
(SELECT c.*,ROW_NUMBER() OVER (ORDER BY id) AS rn
FROM CollegeAttended c
WHERE c.ProfileId = 5574443 AND c.InstanceId = 6559
) t3
USING (rn);
尽管FULL JOIN
和USING
都是标准SQL,但并非所有数据库都支持它们。
如果数据库支持该功能,则可以切换到full join
。如果您的数据库不支持using
,这有点棘手,但是您可以:
SELECT t1.*,ROW_NUMBER() OVER (ORDER BY id) AS rn
FROM Attachment a
WHERE a.ProfileId = 5574443 AND a.InstanceId = 6559
) AS t1
FULL JOIN (
SELECT b.*,ROW_NUMBER() OVER (ORDER BY id) AS rn
FROM Achievement b
WHERE b.ProfileId = 5574443 AND b.InstanceId = 6559
) AS t2 ON t1.rn = t2.rn
FULLL JOIN (
SELECT c.*,ROW_NUMBER() OVER (ORDER BY id) AS rn
FROM CollegeAttended c
WHERE c.ProfileId = 5574443 AND c.InstanceId = 6559
) AS t3 ON COALESCE(t1.rn,t2.rn) = t3.rn