Sql 完全外部联接行为异常
我在同一个sql server数据库中有两个表,它们存储连续两个季度的应用程序名和用户名(以及其他内容)。我想要的是一个完整连接,它显示表a中不在表B中的用户,反之亦然 编辑:表a和表b都包含两个或多个记录,其中AppName和Username的值相同,因此需要使用不同的名称。我编辑了下面的示例以反映这一点 表a:Sql 完全外部联接行为异常,sql,sql-server,Sql,Sql Server,我在同一个sql server数据库中有两个表,它们存储连续两个季度的应用程序名和用户名(以及其他内容)。我想要的是一个完整连接,它显示表a中不在表B中的用户,反之亦然 编辑:表a和表b都包含两个或多个记录,其中AppName和Username的值相同,因此需要使用不同的名称。我编辑了下面的示例以反映这一点 表a: ----------------------- | AppName | Username | ----------------------- | app1 | jdoe
-----------------------
| AppName | Username |
-----------------------
| app1 | jdoe |
| app1 | jsmith |
| app1 | jdoe |
| app2 | jsmith |
-----------------------
表b:
-----------------------
| AppName | Username |
-----------------------
| app1 | fbar |
| app1 | jsmith |
| app1 | jboehner |
| app1 | fbar |
| app3 | jboehner |
-----------------------
SQL:
预期结果:
-----------------------
| q2 | q3 |
-----------------------
| jdoe | |
| jsmith | jsmith |
| | fbar |
-----------------------
| | jboehner |
-----------------------
实际结果:
-----------------------
| q2 | q3 |
-----------------------
| jsmith | jsmith |
-----------------------
什么使???在外部联接表(在本例中是两个表)上使用WHERE子句将其更改为内部联接,因为过滤器应用于联接的结果,并且必须满足所有条件。在您的情况下,这是不可能的,除非是在匹配的行上(它强制它进行内部联接)。我猜这就是你的意思:
SELECT DISTINCT a.username as q2, b.username as q3
FROM dbo.tablea as a
FULL OUTER JOIN dbo.tableb as b
ON a.username = b.username
AND (a.appname = b.appname)
WHERE a.appname = 'app1' OR b.appname = 'app1';
-- or
SELECT DISTINCT a.username as q2, b.username as q3
FROM dbo.tablea as a
FULL OUTER JOIN dbo.tableb as b
ON a.username = b.username
AND (a.appname = b.appname)
WHERE 'app1' IN (a.appname, b.appname);
对外部联接表(在本例中是两个表)使用WHERE子句会将其更改为内部联接,因为过滤器应用于联接的结果,并且必须满足所有条件。在您的情况下,这是不可能的,除非是在匹配的行上(它强制它进行内部联接)。我猜这就是你的意思:
SELECT DISTINCT a.username as q2, b.username as q3
FROM dbo.tablea as a
FULL OUTER JOIN dbo.tableb as b
ON a.username = b.username
AND (a.appname = b.appname)
WHERE a.appname = 'app1' OR b.appname = 'app1';
-- or
SELECT DISTINCT a.username as q2, b.username as q3
FROM dbo.tablea as a
FULL OUTER JOIN dbo.tableb as b
ON a.username = b.username
AND (a.appname = b.appname)
WHERE 'app1' IN (a.appname, b.appname);
应该在哪里,或者不在哪里,以及:
其中a.appname='app1'或b.appname='app1'WHERE应该是或不是,并且:
SELECT DISTINCT a.username as q2, b.username as q3
FROM (SELECT x.* FROM tablea x WHERE x.appname = 'app1') as a
FULL JOIN (SELECT y.* FROM tableb y WHERE y.appname = 'app1') as b
ON a.username = b.username
其中a.appname='app1'或b.appname='app1'
SELECT DISTINCT a.username as q2, b.username as q3
FROM (SELECT x.* FROM tablea x WHERE x.appname = 'app1') as a
FULL JOIN (SELECT y.* FROM tableb y WHERE y.appname = 'app1') as b
ON a.username = b.username
编辑#1:
编辑#2:
编辑#3:
编辑#1:
编辑#2:
编辑#3:
既然您已经在适当的位置创建了带有空值的数据集,您就不能对a.username=b.username和a.appname=b.appname进行完整的外部联接,然后将WHERE条件放在事实之后吗?SQL Server是否能够以这种方式将筛选器推送到各个表中?我习惯于手动将筛选器下推到派生表中。@Love2Learn yes,但重要的是WHERE子句不能对两个表都有AND(这使它成为一个内部联接)。在完全联接的情况下,两个表上都有WHERE子句不会导致内部联接或左外部联接吗?只需将where条件添加到on子句。@Andrew如果只将where子句移动到on,对于除app1之外的其他应用程序,您还将获得不匹配的行-筛选器不适用。由于您已经在适当的位置创建了带有null的数据集,您不能对a.username=b.username和a.appname=b.appname进行完整的外部联接,然后将WHERE条件放在事实之后吗?SQL Server能否推送是否以这种方式过滤到各个表中?我习惯于手动将筛选器下推到派生表中。@Love2Learn yes,但重要的是WHERE子句不能对两个表都有AND(这使它成为一个内部联接)。在完全联接的情况下,两个表上都有WHERE子句不会导致内部联接或左外部联接吗?只需将where条件添加到on子句。@Andrew如果您只将where子句移动到on,您还将获得除app1以外的其他应用程序的不匹配行-筛选器不适用。否,这将允许任一表在
appname“app1”中引入行。
。否,这将允许任何一个表在appname'app1'
@AaronBertrand的位置引入行,如果该表在appname上建立索引,这可能会产生非常有效的计划。如果索引正确,甚至可能导致合并联接而不进行排序。事实上,如果过滤器向外移动,我看不出查询如何变得更快。我很感兴趣。考虑使用巴斯宾.@ AaronBertrand(AppNead,用户名)的索引包括(*)?如果appname上的筛选器具有高度选择性,并且表很大,则include应该是可选的。@AaronBertrand如果表在appname上建立索引,这可能会产生非常有效的计划。如果索引正确,甚至可能导致合并联接而不进行排序。事实上,如果过滤器向外移动,我看不出查询如何变得更快。我很感兴趣。考虑使用巴斯宾.@ AaronBertrand(AppNead,用户名)的索引包括(*)?如果appname上的筛选器具有高度选择性且表很大,则include应该是可选的。
Test #1
{
Table 'ProductModel'. Scan count 0, logical reads 2, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.
Table 'Worktable'. Scan count 0, logical reads 0, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.
Table 'Product'. Scan count 0, logical reads 2, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.
}
Test #2
{
Table 'ProductModel'. Scan count 1, logical reads 2, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.
Table 'Product'. Scan count 1, logical reads 15, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.
}