WHERE子句 - 不显示带有NULL列的记录

时间:2013-06-04 18:50:15

标签: sql-server tsql null where

enter image description here

enter image description here

构想

Org_Structure 中,有部门和办公室的独特组合。在 Emp_Positions 表中,每个员工都被分配到组织结构中的部门/办公室或“Chain”的特定组合。但是一些员工不应该属于办公室,因此他们被分配到 office_id 列为NULL的链。 在第二张图片上,这样的员工用红色着色。

错误

提供的存储过程只能找到dep_id和office_id都为NOT NULL的链的员工。如果在某些记录中office_id为NULL,或者dep_id为NULL,则不会显示此记录。看到第二张图片,结果中从不显示红色记录。一旦我用值替换NULL,就会显示它。如果我用NULL替换任何行的任何列,则不会显示整行。

我试图找到修复它的方法,但我无法弄明白......这里的伙计已经帮助我使这个程序工作了,我非常感谢,但是WHERE子句仍然是错误的......

这是存储过程:

set ANSI_NULLS ON
set QUOTED_IDENTIFIER ON
GO
ALTER PROCEDURE FilterEmpList
    @empName nvarchar(250) = null,
    @empDepID int = null,
    @empOfficeID int = null,
    @empPosID int = null    
AS 
BEGIN
SELECT 
    E.emp_id,
    E.emp_name,      
    P.pos_name,
    D.dep_name,
    O.office_name
FROM dbo.Org_Structure OS 
    JOIN dbo.Emp_Positions EP ON OS.chain_id=EP.chain_id  
    JOIN dbo.Employees E ON EP.emp_id=E.emp_id 
    JOIN dbo.Positions P ON P.pos_id=EP.pos_id
    JOIN dbo.Departments D ON D.dep_id=OS.dep_id
    LEFT JOIN dbo.Offices O ON O.office_id=OS.office_id  
WHERE (E.emp_name LIKE '%'+@empName+'%' OR @empName IS NULL)
    AND OS.dep_id = ISNULL(@empDepID, OS.dep_id)
    AND OS.office_id = ISNULL(@empOfficeID, OS.office_id)
    AND EP.pos_id = ISNULL(@empPosID, EP.pos_id)
END

*添加 LEFT JOIN 后,它仍然无法正常工作

问题已解决

查看评论

1 个答案:

答案 0 :(得分:2)

问题是固定的,但我注意到没有解释为什么它被修复了。所以我们走了:

在SQL中,任何类型的变量都可以接收值NULL。此值表示缺少值或未知值。 NULL是特殊的,因为任何在一侧或两侧使用NULL的相等或不等式运算符的结果不是true或false,而是NULL。

所以:

'Hello' = 'Hello' -> true
'Hello' = 'World' -> false

可是:

'Hello' = NULL -> NULL
NULL = NULL    -> NULL

这意味着SQL使用具有三个可能值的布尔系统。按照这些规则将NULL添加到通常的“true”和“false”:

TRUE  and NULL = NULL
FALSE and NULL = FALSE
NULL  and NULL = NULL

TRUE  or NULL = TRUE
FALSE or NULL = NULL
NULL  or NULL = NULL

NOT NULL = NULL

在这种情况下,如果“office_id”或“dep_id”为NULL,那么条件的结果

OS.dep_id = ISNULL(@empDepID, OS.dep_id)

OS.office_id = ISNULL(@empOfficeID, OS.office_id)

将为NULL。由于具有NULL值的逻辑AND的结果始终为NULL或FALSE,因此处理整个子句子句的结果必须为NULL或FALSE,并且因为只有在子句的结果为TRUE时才返回行,所以没有行归还。