首先推荐一下深入详解SQL中的null(http://blog.csdn.net/renfufei/article/details/44420539) 这篇文章写得比较全面了。
这里我说一下我遇到的问题。
在设计一个存储过程时,我们经常把一个变量查询出来之后,放入一个变量中。
标准做法是,先select 数据赋值给变量。然后再判断变量是否为空。(如果事情到这里,没有问题了。)
当时为了偷懒直接使用了一些函数来处理null。eg:isnull之类的函数。测试过程中发现没有解决问题。
于是我开始了查找问题,先怀疑数据库,再怀疑接口等等等。
结果我在反复调查求证之后,发现由于where条件是false。所以没有结果。进而我在select部分中加的所有函数都无效了。
这就是【结果是空集】与【集合中有一个对象,对象为空集】经典的集合问题了
样例表:
-- ----------------------------
-- Table structure for `test`
-- ----------------------------
DROP TABLE IF EXISTS `test`;
CREATE TABLE `test` (
`TEST_I` int(11) DEFAULT NULL,
`TEST_C` varchar(512) DEFAULT NULL
) ENGINE=InnoDB DEFAULT CHARSET=gbk;
样例数据:
-- ----------------------------
-- Records of test
-- ----------------------------
INSERT INTO `test` VALUES ('1', 'a');
INSERT INTO `test` VALUES ('2', 'b');
样例存储过程(版本1):
DROP PROCEDURE IF EXISTS `PROCEDURE_TEST`;CREATE PROCEDURE `PROCEDURE_TEST`(
_TEST_I int(11) ,
_TEST_C VARCHAR(512)
)
BEGIN
DECLARE _TEST_I_EX int;
SELECT TEST_I INTO _TEST_I_EX FROM TEST WHERE TEST_I = _TEST_I ;
IF _TEST_I <> _TEST_I_EX THEN
INSERT INTO TEST(
TEST_I,
TEST_C
)
VALUES(
_TEST_I,
_TEST_C
);
END IF ;
END;
我立刻判断出来_TEST_I_EX是null引发的问题。于是写了第二个版本的存储过程。
样例存储过程(版本2改进版):
DROP PROCEDURE IF EXISTS `PROCEDURE_TEST`;
CREATE PROCEDURE `PROCEDURE_TEST`(
_TEST_I int(11) ,
_TEST_C VARCHAR(512)
)
BEGIN
DECLARE _TEST_I_EX int;
SELECT nullif(TEST_I,1) INTO _TEST_I_EX FROM TEST WHERE TEST_I = _TEST_I ; /*用函数判断了,当这个值为null的时候*/
IF _TEST_I <> _TEST_I_EX THEN
INSERT INTO TEST(
TEST_I,
TEST_C
)
VALUES(
_TEST_I,
_TEST_C
);
END IF ;
END;
因为查询结果为空,所以函数判断根本没用。