起因是写了一个需要检索int类型字段的条件匹配,原意是参数@Year传''空时Year字段不进行筛选,然后发现查询结果是该字段的数据都查询不到。
Year列本身包含一些为NULL的数据。
Decalre @Year INT
WHERE ISNULL(Year, '') = @Year --原来写的
当我修改成case when 筛选时,又只能筛选到有数值的数据,无数值(null)的数据全部筛选不到。(此处有一个注意点,INT类型的参数传'',实际上参数的数值会自动转换成0)
WHERE (Year = CASE WHEN @Year = 0 THEN Year ELSE @Year END)
后来发现问题出现在这,匹配逻辑存在误区:
在SQL中,
NULL
代表一个未知的或缺失的值。当你在WHERE
子句中进行比较操作时,如果比较的任一侧是NULL
,那么整个比较表达式的结果将不是TRUE
或FALSE
,而是NULL
。在SQL的逻辑中,NULL
不等同于FALSE
,而是表示“未知”,因此它不会满足WHERE
子句的条件。例如,假设你有一个名为
MyColumn
的列,其中有一些NULL
值,如果你运行以下查询:SELECT * FROM MyTable WHERE MyColumn = 123;
那么所有
MyColumn
列中值为123
的行将被选中,而MyColumn
列中的NULL
值将不会被选中,因为NULL = 123
的结果是NULL
,不是TRUE
。同样地,如果你运行:
SELECT * FROM MyTable WHERE MyColumn = MyColumn;
你可能期望这个查询返回所有行,因为任何值和它自己比较都应该是相等的。然而,对于
MyColumn
中的NULL
值,NULL = NULL
的结果也是NULL
,而不是TRUE
。因此,这个查询不会返回那些MyColumn
值为NULL
的行。
回到我的查询,当@Year
参数为0时,我希望返回所有记录,而不考虑Year
的值。但是如果Year字段的值恰好
是NULL
,那么这个比较会变成NULL = NULL
,其结果是NULL
,不满足WHERE
子句的条件。为了确保即使在Year
为NULL
的情况下也能选中所有记录,我需要添加OR @Year = 0
条件,这样当@tYear
为0时,无论Year
的值是什么,包括NULL都会被检索到。
当在 SQL 的 WHERE
子句中使用 OR
时,是在指定两个或多个条件中只要有一个条件满足,整个 WHERE
子句就会被认为是真(TRUE),因此查询会返回那行数据这个OR
条件都会为TRUE
,从而包含所有记录。
--修改为
WHERE (Year = CASE WHEN @Year = 0 THEN Year ELSE @Year END OR @Year = 0)
这是一种常见的技巧,用于在参数值应触发“无过滤”行为时,确保查询不会由于字段中的NULL值而排除任何记录。
varchar类型参数筛选:
WHERE FName LIKE '%' + @Name + '%'
当使用 LIKE
操作符与一个包含通配符 %
的字符串进行比较时,如果变量为空字符串(''),那么表达式会变成:
WHERE ts.FName LIKE '%%'
--这相当于
WHERE ts.FName LIKE '%'
在 SQL 中,百分号
%
是一个通配符,它匹配任何字符序列(包括空字符序列)。因此,当@Name
是空字符串时,LIKE '%'
会匹配ts.FName
中的所有值,包括空字符串,但不包括NULL
。然而,这里需要注意的是,
LIKE
操作符并不会返回字段值为NULL
的行。当列的值是NULL
时,LIKE
操作符会返回UNKNOWN
,这就像其他的比较操作一样,因为NULL
表示未知或缺失的值。如果查询返回了包含
Name
为NULL
的数据,那可能是因为你的查询中有其他的JOIN
或WHERE
条件允许这些行被返回。例如,如果你使用了左连接(LEFT JOIN
),那么即使连接的条件不成立,主表中的行也会被返回,并且连接表中的列会显示为NULL
。
如果你的意图是为了在Name
字段可能包含NULL
值的情况下,也能够正确地执行模糊匹配,那么你可能需要在 WHERE
子句中显式地处理这种情况,例如:
ISNULL(Name, ‘’) LIKE ‘%’+@Name+’%'
ISNULL
函数的作用是,如果GysName
为NULL
,则将其替换为一个空字符串''
,这样即使Name
为NULL
,LIKE
子句也能够执行,因为空字符串与任何模式匹配都是有效的。
例如,如果@Name的值是'ABC',那么ISNULL(Name, '') LIKE '%'+@Name+'%'会变成:
如果Name是NULL,则变为'' LIKE '%ABC%',这通常是FALSE(除非@Name也是空字符串)。
如果Name是非NULL值,比如'XYZABC',则变为'XYZABC' LIKE '%ABC%',这是TRUE。
INT
类型的字段和字符串类型的字段在 SQL 中的匹配规差异主要体现在以下几点:
比较运算符:
- 对于
INT
类型的字段,通常使用的比较运算符包括=
,!=
,<
,>
,<=
,>=
等。- 对于字符串类型的字段,除了上述比较运算符,还经常使用
LIKE
运算符进行模糊匹配。LIKE
运算符可以与通配符%
(匹配任意字符序列)和_
(匹配任意单个字符)一起使用。NULL 值的处理:
- 当
INT
类型字段比较时,如果字段值为NULL
,则任何与NULL
的比较都会返回NULL
,这在布尔上下文中被视为FALSE
,不满足WHERE
子句的条件。- 当字符串字段使用
LIKE
进行模糊匹配时,如果字段值为NULL
,同样任何与NULL
的比较都会返回NULL
。但是,如果比较的字符串是空字符串''
,则%
会匹配空字符串,因此LIKE '%'
会匹配所有非NULL
字符串值。空字符串与 NULL:
- 在
INT
类型字段中,不存在空字符串的概念,字段要么有具体的整数值,要么是NULL
。- 在字符串类型字段中,空字符串
''
和NULL
是不同的。空字符串是一个有效的值,表示没有字符,而NULL
表示值未知或缺失。