NOT IN 与连接列
NOT IN vs concatenate columns
SQL下面的两个不一样吗?我的意思是功能明智应该做同样的事情?
我期待这第一个 SQL 应该也有结果。
SELECT *
FROM #TEST
WHERE COL1 NOT IN (SELECT COL1 FROM #TEST_1)
AND COL2 NOT IN (SELECT COL2 FROM #TEST_1)
--1 record
SELECT *
FROM #TEST
WHERE COL1 + COL2 NOT IN (SELECT COL1 +COL2 FROM #TEST_1)
CREATE TABLE #TEST
(
COL1 VARCHAR(10),
COL2 VARCHAR(10),
COL3 VARCHAR(10)
)
INSERT INTO #TEST VALUES ('123', '321', 'ABC')
INSERT INTO #TEST VALUES ('123', '436', 'ABC')
CREATE TABLE #TEST_1
(
COL1 VARCHAR(10),
COL2 VARCHAR(10),
COL3 VARCHAR(10)
)
INSERT INTO #TEST_1 VALUES ( '123','532','ABC')
INSERT INTO #TEST_1 VALUES ( '123','436','ABC')
--No result
SELECT *
FROM #TEST
WHERE COL1 NOT IN (SELECT COL1 FROM #TEST_1)
AND COL2 NOT IN (SELECT COL2 FROM #TEST_1)
--1 record
SELECT *
FROM #TEST
WHERE COL1 + COL2 NOT IN (SELECT COL1 + COL2 FROM #TEST_1)
让我们把它放到更多的上下文中,看看你的 2 个 WHERE
子句,我将分别称之为“WHERE 1”和“WHERE 2”:
--WHERE 1
WHERE COL1 NOT IN (SELECT COL1 FROM #TEST_1)
AND COL2 NOT IN (SELECT COL2 FROM #TEST_1)
--WHERE 2
WHERE COL1 + COL2 NOT IN (SELECT COL1 + COL2 FROM #TEST_1)
您可能已经注意到,此 do 的行为不同。事实上,从逻辑角度和数据库引擎处理它们的方式来看,它们完全不同。
WHERE 2,首先是 not SARGable。这意味着您的 table 上的任何索引都将无法使用,数据引擎将不得不扫描 整个 table。但是,对于 WHERE 1,它 是 SARGable,如果您有任何索引,它们可用于执行查找,可能有助于提高性能。
从逻辑的角度来看,我们先看WHERE 2。这要求 COL1
和 COL2
的连接值不匹配 COL1
和 COL2
的另一个连接值;这意味着这些值必须在同一行。因此 '123456'
仅当 Col1
具有值 '123'
且 Col2
具有值 '456'
.
时才会匹配
然而对于WHERE 1,这里Col1
的值需要在另一个table中找不到,Col2
也需要找不到,但是他们可以在 不同的 行。这就是不同之处。由于 Col1
中的 '123'
出现在两个 table 中(并且是唯一的值),因此 NOT IN
未满足并且不返回任何行。
如果您想要 WHERE 2 的 SARGable 版本,我建议使用 EXISTS
:
--1 row
SELECT T.COL1, --Don't use *, specify your columns
T.COL2, --Qualifying your columns is important!
T.COL3
FROM #TEST T --Aliasing is important!
WHERE NOT EXISTS (SELECT 1
FROM #TEST_1 T1
WHERE T1.COL1 = T.COL1
AND T1.COL2 = T.COL2);
当您以这种方式添加字符串时(使用 +
而不是 concatenation
),它会添加两个字符串并为您提供数值。
在第一个查询中,您没有添加字符串,所以您所做的是:
Select all rows from #Test that values of Col1 and Col2 are not in Test1
实际上,只有第一个参数会删除所有内容,因为您在 col1.
的两个表中都有 123 个值
第二个查询对该字符串求和,但不是通过串联求和。
它实际上在幕后将 varchars 转换为数字。
所以第二个查询是:
Select all rows from #test where COL1+COL2 (its 444 at first row, and 559 in second row) are not in #Test 1
如果您在#Test1 添加行,则值为:
For the first row COL1+COL2= 655
For the second row COL1+COL2= 559
所以只有总和为 444 的行不在 #Test1
,这就是为什么你得到 1 行作为结果。
总结一下:
这就是为什么您在第二次查询中只看到 1 行,而在第一次查询中看不到任何记录的原因。在第一个查询中,只有第一个条件真正有效并削减了一切。在第二个查询中 SQL 引擎正在将 varchars 转换为数字。
所以'123'+'321'不是'123321'而是'444'。
SQL下面的两个不一样吗?我的意思是功能明智应该做同样的事情?
我期待这第一个 SQL 应该也有结果。
SELECT *
FROM #TEST
WHERE COL1 NOT IN (SELECT COL1 FROM #TEST_1)
AND COL2 NOT IN (SELECT COL2 FROM #TEST_1)
--1 record
SELECT *
FROM #TEST
WHERE COL1 + COL2 NOT IN (SELECT COL1 +COL2 FROM #TEST_1)
CREATE TABLE #TEST
(
COL1 VARCHAR(10),
COL2 VARCHAR(10),
COL3 VARCHAR(10)
)
INSERT INTO #TEST VALUES ('123', '321', 'ABC')
INSERT INTO #TEST VALUES ('123', '436', 'ABC')
CREATE TABLE #TEST_1
(
COL1 VARCHAR(10),
COL2 VARCHAR(10),
COL3 VARCHAR(10)
)
INSERT INTO #TEST_1 VALUES ( '123','532','ABC')
INSERT INTO #TEST_1 VALUES ( '123','436','ABC')
--No result
SELECT *
FROM #TEST
WHERE COL1 NOT IN (SELECT COL1 FROM #TEST_1)
AND COL2 NOT IN (SELECT COL2 FROM #TEST_1)
--1 record
SELECT *
FROM #TEST
WHERE COL1 + COL2 NOT IN (SELECT COL1 + COL2 FROM #TEST_1)
让我们把它放到更多的上下文中,看看你的 2 个 WHERE
子句,我将分别称之为“WHERE 1”和“WHERE 2”:
--WHERE 1
WHERE COL1 NOT IN (SELECT COL1 FROM #TEST_1)
AND COL2 NOT IN (SELECT COL2 FROM #TEST_1)
--WHERE 2
WHERE COL1 + COL2 NOT IN (SELECT COL1 + COL2 FROM #TEST_1)
您可能已经注意到,此 do 的行为不同。事实上,从逻辑角度和数据库引擎处理它们的方式来看,它们完全不同。
WHERE 2,首先是 not SARGable。这意味着您的 table 上的任何索引都将无法使用,数据引擎将不得不扫描 整个 table。但是,对于 WHERE 1,它 是 SARGable,如果您有任何索引,它们可用于执行查找,可能有助于提高性能。
从逻辑的角度来看,我们先看WHERE 2。这要求 COL1
和 COL2
的连接值不匹配 COL1
和 COL2
的另一个连接值;这意味着这些值必须在同一行。因此 '123456'
仅当 Col1
具有值 '123'
且 Col2
具有值 '456'
.
然而对于WHERE 1,这里Col1
的值需要在另一个table中找不到,Col2
也需要找不到,但是他们可以在 不同的 行。这就是不同之处。由于 Col1
中的 '123'
出现在两个 table 中(并且是唯一的值),因此 NOT IN
未满足并且不返回任何行。
如果您想要 WHERE 2 的 SARGable 版本,我建议使用 EXISTS
:
--1 row
SELECT T.COL1, --Don't use *, specify your columns
T.COL2, --Qualifying your columns is important!
T.COL3
FROM #TEST T --Aliasing is important!
WHERE NOT EXISTS (SELECT 1
FROM #TEST_1 T1
WHERE T1.COL1 = T.COL1
AND T1.COL2 = T.COL2);
当您以这种方式添加字符串时(使用 +
而不是 concatenation
),它会添加两个字符串并为您提供数值。
在第一个查询中,您没有添加字符串,所以您所做的是:
Select all rows from #Test that values of Col1 and Col2 are not in Test1
实际上,只有第一个参数会删除所有内容,因为您在 col1.
第二个查询对该字符串求和,但不是通过串联求和。 它实际上在幕后将 varchars 转换为数字。 所以第二个查询是:
Select all rows from #test where COL1+COL2 (its 444 at first row, and 559 in second row) are not in #Test 1
如果您在#Test1 添加行,则值为:
For the first row COL1+COL2= 655
For the second row COL1+COL2= 559
所以只有总和为 444 的行不在 #Test1
,这就是为什么你得到 1 行作为结果。
总结一下:
这就是为什么您在第二次查询中只看到 1 行,而在第一次查询中看不到任何记录的原因。在第一个查询中,只有第一个条件真正有效并削减了一切。在第二个查询中 SQL 引擎正在将 varchars 转换为数字。
所以'123'+'321'不是'123321'而是'444'。