Sql 让并集显示彼此旁边的值,而不是彼此下面的值

Sql 让并集显示彼此旁边的值,而不是彼此下面的值,sql,sql-server,Sql,Sql Server,我得到了一个SQL查询,它显示了两个表中的值。现在,我想让这个表从两个不同的表中选择彼此之外的值。这是我现在的问题: (select i1,i2 from t1 except select i1,i2 from t2) union all (select i1,i2 from t2 except select i1,i2 from t1) 这是我的示例数据: 表1中的数据: i1 i2 --------- | 1 | 1 | --------- | 2 | 2 | --------- |

我得到了一个SQL查询,它显示了两个表中的值。现在,我想让这个表从两个不同的表中选择彼此之外的值。这是我现在的问题:

(select i1,i2 from t1
except
select i1,i2 from t2)
union all
(select i1,i2 from t2
except
select i1,i2 from t1)
这是我的示例数据:

表1中的数据:

 i1   i2
---------
| 1 | 1 |
---------
| 2 | 2 |
---------
| 2 | 3 |
---------
表2中的数据:

 i1   i2
---------
| 1 | 1 |
---------
| 2 | 3 |
---------
| 2 | 4 |
---------
结果:

---------
| 2 | 2 |  << this one comes from table 1
---------
| 2 | 4 |  << this one comes from table 2
---------

您可以使用
交叉联接
不存在
来执行此操作:

SELECT *
FROM t1 a
CROSS JOIN t2 b
WHERE NOT EXISTS (SELECT 1
                  FROM t2 c
                  WHERE a.i1 = c.i1 
                    AND a.i2 = c.i2
                  )
  AND NOT EXISTS (SELECT 1
                  FROM t1 c
                  WHERE b.i1 = c.i1 
                    AND b.i2 = c.i2
                  )

交叉连接
将一个表中的每条记录与另一个表中的每条记录连接起来,因此返回每一行的组合
NOT EXISTS
用于从
t1
中筛选出出现在
t2
中的记录,反之亦然。对于第二个
NOT EXISTS

我认为最好的方法是使用
完全连接
,然后使用
NULL
数据执行
WHERE
。因为如果您进行
交叉联接
,您将获得比您需要的更多的数据

SELECT *
FROM t1
FULL JOIN t2
    ON t1.i1 = 2.i1
        AND t1.i2 = t2.i2
WHERE t1.Id IS NULL
    OR t2.Id IS NULL
我将用一个例子来解释:

IF OBJECT_ID('tempdb..#t1') IS NOT NULL
            DROP TABLE #t1

CREATE TABLE #t1
(
    Id INT IDENTITY,
    i1 INT,
    i2 INT
)

INSERT INTO #t1
(
    i1,i2
)
VALUES
(1,1)
,(2,2)
,(2,3)
,(2,6)

SELECT * FROM #t1

IF OBJECT_ID('tempdb..#t2') IS NOT NULL
            DROP TABLE #t2

CREATE TABLE #t2
(
    Id INT IDENTITY,
    i1 INT,
    i2 INT
)

INSERT INTO #t2
(
    i1,i2
)
VALUES
(1,1)
,(2,3)
,(2,4)
,(2,5)
,(2,7)

SELECT * FROM #t2


SELECT *
FROM #t1
FULL JOIN #t2
    ON #t1.i1 = #t2.i1
        AND #t1.i2 = #t2.i2
WHERE #t1.Id IS NULL
    OR #t2.Id IS NULL

SELECT *
FROM #t1 a
CROSS JOIN #t2 b
WHERE NOT EXISTS (SELECT 1
                  FROM #t2 c
                  WHERE a.i1 = c.i1 
                    AND a.i2 = c.i2
                  )
  AND NOT EXISTS (SELECT 1
                  FROM #t1 c
                  WHERE b.i1 = c.i1 
                    AND b.i2 = c.i2
                  )
结果

在第一种情况下,您将得到5条记录,因为(2,2)和(2,6)在t2中不存在,而(2,4)、(2,5)、(2,7)在t1中不存在。所以你会有5个结果

Id          i1          i2          Id          i1          i2
----------- ----------- ----------- ----------- ----------- -----------
2           2           2           NULL        NULL        NULL
4           2           6           NULL        NULL        NULL
NULL        NULL        NULL        3           2           4
NULL        NULL        NULL        4           2           5
NULL        NULL        NULL        5           2           7

(5 row(s) affected)
然而,在交叉连接中,你会得到6个结果,因为你会得到一个笛卡尔积。2x3=6

试一试


这叫做“加入”。这不是目的,也不是工会的运作方式。使用带有NOT EXISTS子句的join。好吧,我明白了,对不起,伙计们,我应该删除这个问题吗?我不认为这是个坏问题,只是很难理解您的数据示例,如果它们有列标题可能会更好。在这一点上与@HartCO达成一致。你只是因为问一些基本的问题而受到一些连续的投票人的反对,但是列标题会有很大帮助。如果用户有更多的数据,那么会返回比需要更多的记录。我会制作一个笛卡尔产品,我认为用户不需要。您可能低估了查询优化器,但我希望看到一个返回所需输出的替代方案。我曾想过使用完全联接,但要使“2,2”记录与“2,4”记录在同一行上,您必须使用
,然后,您仍然需要使用
NOT EXIST
s过滤不需要的行。@HartCO感谢您的评论。我会检查的@哈特科是的,我同意你的看法。我要求用户提供更多细节,以防他添加更多记录。所以我可以更好地了解您想要的是什么。它返回的交叉连接结果相同,不是吗?
Id          i1          i2          Id          i1          i2
----------- ----------- ----------- ----------- ----------- -----------
2           2           2           NULL        NULL        NULL
4           2           6           NULL        NULL        NULL
NULL        NULL        NULL        3           2           4
NULL        NULL        NULL        4           2           5
NULL        NULL        NULL        5           2           7

(5 row(s) affected)
Id          i1          i2          Id          i1          i2
----------- ----------- ----------- ----------- ----------- -----------
2           2           2           3           2           4
2           2           2           4           2           5
2           2           2           5           2           7
4           2           6           3           2           4
4           2           6           4           2           5
4           2           6           5           2           7

(6 row(s) affected)
SELECT *
FROM 
    (
        SELECT i1, i2
        FROM t1

        EXCEPT

        SELECT i1, i2
        FROM t2
    ) a, 
    (
        SELECT i1, i2
        FROM t2

        EXCEPT

        SELECT i1, i2
        FROM t1
    ) b