SQL 服务器中 "Except All" 的替代方案

Alternative for "Except All" in SQL Server

标准 SQL 定义 EXCEPT ALL 其操作如下 (Postgres fiddle)

CREATE TABLE T1(X INT);

CREATE TABLE T2(X INT);

INSERT INTO T1 VALUES (1),(1),(2);

INSERT INTO T2 VALUES (1),(2);

SELECT X
FROM T1
EXCEPT ALL
SELECT X
FROM T2

这个returns

+---+
| X |
+---+
| 1 |
+---+

因为 T1T2 中多了一个 1 行。

SQL 服务器只允许 EXCEPT

SELECT X
FROM T1
EXCEPT 
SELECT X
FROM T2

returns 空结果集。我如何实施 EXCEPT ALL?

尝试使用 where not exists 子句,这将使您无法获得不同的列表。

Use AdventureWorks2017;
Go

Create Table #A (a int, b varchar(1))
Insert into #A (a, b)
Select 1, 'A' UNION ALL
Select 1, 'A' UNION ALL
Select 1, 'A' UNION ALL
Select 2, 'B'

Create Table #B (a int, b varchar(1))
Insert into #B (a, b)
Select 2, 'B'


Select a, b 
FROM #A 
EXCEPT
Select a, b
From #B

Select a, b
from #A as a where not exists (Select 1 from #B as b
where a.a = b.a and a.b = b.b)

您可以通过运行上述代码看到where not exists子句和except子句之间的不同结果集。

希望对您有所帮助。

By definitionEXCEPT returns 来自左侧输入查询但右侧输入查询未输出的不同行。

SQL Fiddle

MS SQL Server 2017 架构设置:

CREATE TABLE MyTableA (ColA int, ColB int)
CREATE TABLE MyTableB (ColA int, ColB int)
INSERT INTO MyTableA (ColA, ColB) VALUES (15,1),(10,1),(2,1),(2,1),(16,1),(2,2),(3,3),(3,3)
INSERT INTO MyTableB (ColA, ColB) VALUES (1,1),(1,1),(1,1),(2,2),(4,5),(1,1),(4,5)

查询 1:

SELECT * FROM MyTableA
EXCEPT
SELECT * FROM MyTableB

Results:

| ColA | ColB |
|------|------|
|    2 |    1 |
|    3 |    3 |
|   10 |    1 |
|   15 |    1 |
|   16 |    1 |

查询 2:

Select *
from MyTableA as a where not exists (Select 1 from MyTableB as b
where a.ColA = b.ColA and a.ColB = b.ColB)

Results:

| ColA | ColB |
|------|------|
|   15 |    1 |
|   10 |    1 |
|    2 |    1 |
|    2 |    1 |
|   16 |    1 |
|    3 |    3 |
|    3 |    3 |

EXCEPT ALL SQL 服务器不支持。随着表格

t1

a | b
--+--
1 | 1
1 | 1
1 | 1
1 | 2
1 | 2
1 | 3

t2

a | b
--+--
1 | 1
1 | 2
1 | 4

查询

select a, b from t1
except all
select a, b from t2
order by a, b;

会return

a | b
--+--
1 | 1
1 | 1
1 | 2
1 | 3

因为 t1 比 t2 多两 (1|1) 行,多 (1|2) 行和多 (1|3) 行。

要在 SQL 服务器中实现相同的效果,请对行进行编号:

select a, b from
(
  select a, b, row_number() over (partition by a, b order by a) as rn from t1
  except
  select a, b, row_number() over (partition by a, b order by a) as rn from t2
) evaluated
order by a, b;