我有两个带连接和where子句的表。 2个表的示例内容:
Id FieldA Id FieldB
1 100 1 Yellow
2 100 2 Green
3 200 3 Green
4 200 4 Blue
5 300 5 Yellow
6 300 6 Orange
我试图返回除了fieldA = 200 AND fieldB = Green之外的所有内容。所以它仍然应该返回具有fieldA = 100和FieldB = Green的第2行。但是,这是我的查询,它不起作用。它排除了200和绿色的所有行:
select t1.FieldA, t2.FieldB
FROM test1 t1
JOIN test2 t2 ON t1.Id = t2.Id
WHERE (t1.FieldA <> 200 AND t2.FieldB <> 'Green')
我看到它的方式,在运行此查询后,排除的唯一行应该是第3行,因为它有fielda = 200和fieldb = green,但它只返回row1,第5行和&amp; ROW6。在我看来,如果我使用OR,它应该只会这样做。
让我知道我哪里出错了,这里有一些DDL,所以你可以玩它:
create table dbo.test1
(
Id int not null,
FieldA int
)
create table dbo.test2
(
Id int not null,
FieldB varchar(10)
)
INSERT INTO test1 (Id, FieldA)
VALUES
(1,100),
(2,100),
(3,200),
(4,200),
(5,300),
(6,300)
INSERT INTO test2 (Id, FieldB)
VALUES
(1,'Yellow'),
(2,'Green'),
(3,'Green'),
(4,'Blue'),
(5,'Yellow'),
(6,'Orange')
答案 0 :(得分:4)
每个条件都是针对整个行集独立评估的。要合并它们,请翻转操作符并取消组合,如下所示:
select t1.FieldA, t2.FieldB
FROM test1 t1
JOIN test2 t2 ON t1.Id = t2.Id
WHERE not (t1.FieldA = 200 AND t2.FieldB = 'Green')
您的原始查询基本上是说,首先消除FieldA不是200的所有行,然后从剩余的行中消除所有FieldB不是“绿色”的行。
当您希望两个条件都适用于给定行时,首先要选择要排除的条件,这就是您从<>
切换到=
,然后生成{{1 }}子句通过应用WHERE
运算符排除整个事物。
编辑重新评论
我认为关于原始查询返回的结果的混淆以及括号中的条件被“评估为一个”的想法可能源于逻辑否定不是分配的事实,即NOT
的否定是不是A && B
,而是~A && ~B
。
您描述所需结果的第一句话非常接近查询的正确t-sql。你说“我试图返回除了fieldA = 200和fieldB = Green之外的所有东西。”句子的最后一部分是你的where子句,即
~(A && B)
将“not”替换为“except”
except where fieldA = 200 AND fieldB = Green
并将其清理为有效的t-sql语法
not where fieldA = 200 AND fieldB = Green
-- or, to make the grouping explicit
not (where fieldA = 200 AND fieldB = Green)
相比之下,相当于where not (fieldA = 200 AND fieldB = Green)
的英语可能是:返回field1除了200以外的所有内容,而field1是绿色的。在这种情况下,匹配200或绿色就足以排除该行。
要查看错误地排除第2行和第4行的原因,请考虑原始where子句的真值表:
WHERE (t1.FieldA <> 200 AND t2.FieldB <> 'Green')
换句话说,第2行被排除在 Field1 <> 200
T F
-----------------
T | T | F |
| | row 4 |
Field2 <> 'Green' -----------------
F | F | F |
| row 2 | |
-----------------
之后,条件Field2 = 'Green'
评估为Field2 <> 'Green'
,因此FALSE
是什么并不重要,因为{ {1}}和任何其他值始终为Field1
。
答案 1 :(得分:2)
当你在Id上进行连接时,它会创建一个临时表,如下所示
Id FieldA FieldB
1 100 Yellow
2 100 Green
3 200 Green
4 200 Blue
5 300 Yellow
6 300 Orange
当你说FieldA&lt;&gt;在图200中,行3和4被排除,剩余的行将是1,2,5,6。
现在,当你说FieldB&lt;&gt;绿色,然后第2行被排除,导致行1,5,6。
注意:条件&#39;其中&#39;条款不会根据您指定的顺序应用。相反,它在运行时应用于sql执行计划,并且指定where条件的顺序不会对结果产生任何影响。
要获得结果,请使用以下条件
select t1.FieldA, t2.FieldB
FROM test1 t1
JOIN test2 t2 ON t1.Id = t2.Id
WHERE NOT (t1.FieldA = 200 AND t2.FieldB = 'Green')
答案 2 :(得分:1)
select t1.FieldA, t2.FieldB
FROM test1 t1
JOIN test2 t2 ON t1.Id = t2.Id
WHERE NOT (t1.FieldA = 200 AND t2.FieldB = 'Green')
答案 3 :(得分:0)
咧嘴笑,你可以尝试一下吗?
select t1.FieldA, t2.FieldB
FROM test1 t1
JOIN test2 t2
ON t1.Id = t2.Id
AND t1.FieldA <> 200
AND t2.FieldB <> 'Green'