+ -
当前位置:首页 → 问答吧 → 請問一個mysql抓取不等於0000-00-00的問題

請問一個mysql抓取不等於0000-00-00的問題

时间:2010-07-12

来源:互联网

请教各位前辈,如果我要抓某日期栏位的值不等於NULL或0000-00-00,请问我该怎样抓

以下是我目前使用的方法,而且也正常可以使用,不过我想请问这样是正确的做法吗:

SELECT
*
FROM
`a`
WHERE
 `d` IS NOT NULL
  AND `d` <> '0000-00-00'

谢谢各位

作者: itw   发布时间: 2010-07-12

引用自: itw 於 2010-07-12 11:58
请教各位前辈,如果我要抓某日期栏位的值不等於NULL或0000-00-00,请问我该怎样抓

以下是我目前使用的方法,而且也正常可以使用,不过我想请问这样是正确的做法吗:

SELECT
*
FROM
`a`
WHERE
 `d` IS NOT NULL
  AND `d` <> '0000-00-00'

谢谢各位

最好还是要把好关,前面的程式要把日期栏位处理好. 不然以后你的系统会因为这些错误的日期资料付出很大的代价,若是跟商务有关的话,更是要谨慎.
'0000-00-00' 是format 没设定好产生的结果,建议你把这些都update为NULL.  但还是建议你最好检查一下前面的程式,尽量不要让这种情形发生,
要是不确定就是输入NULL.若是user有输入,但是因为程式的问题,变为'0000-00-00', 那很容易产生纠纷的.
年纪大了,讲话有点囉唆,多多包涵. 

作者: bunko   发布时间: 2010-07-12

做了一些实验:

mysql> create table datefoo (realdate date, foodate char(10));

程式码: sql
mysql> INSERT INTO datefoo VALUES
(str_to_date('0000-00-00','%Y-%m-%d'), '0000-00-00' ),
(str_to_date('1900-02-29','%Y-%m-%d'), '1900-02-29'),
(str_to_date('2100-02-30','%Y-%m-%d'), '2100-02-30'),
(str_to_date('2100-02-31','%Y-%m-%d'), '2100-02-31'),
(str_to_date('2100-02-32','%Y-%m-%d'), '2100-02-32'),
(str_to_date('2010-07-12','abc'), 'bad format'),
(str_to_date('Invaild Date','%Y-%m-%d'), 'InvaildDat'),
(str_to_date('2100-14-01','%Y-%m-%d'), '2100-14-01');

mysql> select * from datefoo;
+------------+------------+
| realdate   | foodate    |
+------------+------------+
| 0000-00-00 | 0000-00-00 |
| 0000-00-00 | 1900-02-29 |
| 0000-00-00 | 2100-02-30 |
| 0000-00-00 | 2100-02-31 |
| NULL           | 2100-02-32 |
| NULL           | bad format  |
| NULL           | InvaildDat   |
| NULL           | 2100-14-01 |
+------------+------------+
8 rows in set (0.00 sec)

从这实验可以看出一些端倪, 0000-00-00 与 NULL 都是代表Invalid Date, 但是会存NULL的就是很直接就能判断是错误的, 如 32日,当然45日也会一样;
或是14月;或是根本就是字串;或是format字串错误.
0000-00-00 的有直接指定就是要存0000-00-00,或是第一道判断(return null)尚未能决定,但是第二道判断判定有误.如2月30日,2月31日;或是非闰年的2月29日.

作者: bunko   发布时间: 2010-07-12


推测楼主可能就是直接insert into 进table,进而产生0000-00-00

mysql> insert into datefoo values
    -> ('2007-02-29','2007-02-29');
Query OK, 1 row affected, 1 warning (0.00 sec)

会产生0000-00-00.
MySQL有str_to_date(), 可是刚才我们也使用此函数,但是 1900-02-29 也是进去mysql后,被转为0000-00-00了.
我们再试一下str_to_date(),

mysql> insert into datefoo values(str_to_date('2010-04-31','%Y-%m-%d'), '2010-04-31');
Query OK, 1 row affected, 1 warning (0.03 sec)

mysql> select * from datefoo
    -> where foodate='2007-02-29' or foodate='2010-04-31';
+------------+------------+
| realdate   | foodate    |
+------------+------------+
| 0000-00-00 | 2007-02-29 |
| 0000-00-00 | 2010-04-31 |
+------------+------------+
2 rows in set (0.10 sec)

由上面的结果可以得知,str_to_date()并不会帮我们完全判断日期是否正确,只能做到部份功能,
下面的实验也能看出str_to_date()的限制所在.

mysql> select str_to_date('2010-04-31','%Y-%m-%d');
+--------------------------------------+
| str_to_date('2010-04-31','%Y-%m-%d') |
+--------------------------------------+
| 2010-04-31                           |
+--------------------------------------+
1 row in set (0.00 sec)

mysql> select str_to_date('2010-04-32','%Y-%m-%d');
+--------------------------------------+
| str_to_date('2010-04-32','%Y-%m-%d') |
+--------------------------------------+
| NULL                                 |
+--------------------------------------+
1 row in set, 1 warning (0.00 sec)

===============================

为了加强日期检查的功能,我们发展自己的函数来增强.
以下为测试过程:

先修改一下测试的table.

mysql> ALTER TABLE datefoo ADD COLUMN isdate BOOLEAN;
Query OK, 10 rows affected (0.14 sec)

以下为检查是否为valid date的函数,mychk_date()
-------------------------------------------
DELIMITER $$

DROP FUNCTION IF EXISTS `mysample`.`mychk_date`$$
CREATE FUNCTION `mysample`.`mychk_date` (indate date) RETURNS boolean
BEGIN
DECLARE rtn boolean;

IF indate = DATE_SUB(DATE_ADD(indate,INTERVAL 1 DAY),INTERVAL 1 DAY) THEN
  SET rtn = TRUE;
ELSE
  SET rtn = FALSE;
END IF;
RETURN rtn;
END$$

DELIMITER ;
-------------------------------------------

INSERT 一些正常的日期进去datefoo,好进行测试.
mysql> insert into datefoo(realdate,foodate)
    -> values(now(),'2010-07-12');
mysql> insert into datefoo(realdate,foodate) values(str_to_date('2010-06-25','%Y-%m-%d'),'2010-06-25');

mysql> select * from datefoo;
+------------+------------+--------+
| realdate   | foodate    | isdate |
+------------+------------+--------+
| 0000-00-00 | 0000-00-00 |   NULL |
| 0000-00-00 | 1900-02-29 |   NULL |
| 0000-00-00 | 2100-02-30 |   NULL |
| 0000-00-00 | 2100-02-31 |   NULL |
| NULL       | 2100-02-32 |   NULL |
| NULL       | bad format |   NULL |
| NULL       | InvaildDat |   NULL |
| NULL       | 2100-14-01 |   NULL |
| 0000-00-00 | 2007-02-29 |   NULL |
| 0000-00-00 | 2010-04-31 |   NULL |
| 2010-07-12 | 2010-07-12 |   NULL |
| 2010-06-25 | 2010-06-25 |   NULL |
+------------+------------+--------+
12 rows in set (0.01 sec)

接下来就使用mychk_date()来进行检查.
mysql> UPDATE datefoo SET isdate=mychk_date(realdate);
Query OK, 12 rows affected, 6 warnings (0.04 sec)
Rows matched: 12  Changed: 12  Warnings: 0

mysql> select * from datefoo;
+------------+------------+--------+
| realdate   | foodate    | isdate |
+------------+------------+--------+
| 0000-00-00 | 0000-00-00 |      0 |
| 0000-00-00 | 1900-02-29 |      0 |
| 0000-00-00 | 2100-02-30 |      0 |
| 0000-00-00 | 2100-02-31 |      0 |
| NULL       | 2100-02-32 |      0 |
| NULL       | bad format |      0 |
| NULL       | InvaildDat |      0 |
| NULL       | 2100-14-01 |      0 |
| 0000-00-00 | 2007-02-29 |      0 |
| 0000-00-00 | 2010-04-31 |      0 |
| 2010-07-12 | 2010-07-12 |      1 |
| 2010-06-25 | 2010-06-25 |      1 |
+------------+------------+--------+
12 rows in set (0.00 sec)

使用mychk_date()进行日期检查.
mysql> SELECT mychk_date(str_to_date('2010-02-29','%Y-%m-%d'));
+--------------------------------------------------+
| mychk_date(str_to_date('2010-02-29','%Y-%m-%d')) |
+--------------------------------------------------+
|                                                0 |
+--------------------------------------------------+
1 row in set, 2 warnings (0.00 sec)

mysql> SELECT mychk_date(str_to_date('2010-07-12','%Y-%m-%d'));
+--------------------------------------------------+
| mychk_date(str_to_date('2010-07-12','%Y-%m-%d')) |
+--------------------------------------------------+
|                                                1 |
+--------------------------------------------------+
1 row in set (0.01 sec)

*********************************************************
接下来我们还要再发展一个检查string是否能转换为valid date的函数.
其实就是把刚才的mychk_date()加工一下就可以了.
函数如下:
-------------------------------------------------------
DELIMITER $$

DROP FUNCTION IF EXISTS `mysample`.`mychk_str_date`$$
CREATE FUNCTION `mysample`.`mychk_str_date` (strdate char(10)) RETURNS boolean
BEGIN
DECLARE rtn boolean;
DECLARE indate DATE;

SET indate = STR_TO_DATE(strdate,'%Y-%m-%d');
IF indate = DATE_SUB(DATE_ADD(indate,INTERVAL 1 DAY),INTERVAL 1 DAY) THEN
  SET rtn = TRUE;
ELSE
  SET rtn = FALSE;
END IF;
RETURN rtn;

END$$

DELIMITER ;
-------------------------------------------------------
修改一下datefoo,再增加一个栏位.
mysql> ALTER TABLE datefoo ADD COLUMN isdate2 BOOLEAN;

mysql> UPDATE datefoo SET isdate2=mychk_str_date(foodate);
Query OK, 12 rows affected, 15 warnings (0.00 sec)
Rows matched: 12  Changed: 12  Warnings: 5

mysql> SELECT * FROM datefoo;
+------------+------------+--------+---------+
| realdate   | foodate    | isdate | isdate2 |
+------------+------------+--------+---------+
| 0000-00-00 | 0000-00-00 |      0 |       0 |
| 0000-00-00 | 1900-02-29 |      0 |       0 |
| 0000-00-00 | 2100-02-30 |      0 |       0 |
| 0000-00-00 | 2100-02-31 |      0 |       0 |
| NULL       | 2100-02-32 |      0 |       0 |
| NULL       | bad format |      0 |       0 |
| NULL       | InvaildDat |      0 |       0 |
| NULL       | 2100-14-01 |      0 |       0 |
| 0000-00-00 | 2007-02-29 |      0 |       0 |
| 0000-00-00 | 2010-04-31 |      0 |       0 |
| 2010-07-12 | 2010-07-12 |      1 |       1 |
| 2010-06-25 | 2010-06-25 |      1 |       1 |
+------------+------------+--------+---------+
12 rows in set (0.00 sec)

mysql> SELECT mychk_str_date('2010-02-29');
+------------------------------+
| mychk_str_date('2010-02-29') |
+------------------------------+
|                            0 |
+------------------------------+
1 row in set, 2 warnings (0.00 sec)

mysql> SELECT mychk_str_date('2010-05-38');
+------------------------------+
| mychk_str_date('2010-05-38') |
+------------------------------+
|                            0 |
+------------------------------+
1 row in set, 1 warning (0.00 sec)

mysql> SELECT mychk_str_date('2010-07-12');
+------------------------------+
| mychk_str_date('2010-07-12') |
+------------------------------+
|                            1 |
+------------------------------+
1 row in set (0.00 sec)

经过以上的实验,我们的mychk_str_date()可以将输入的string检查是否是正确的日期.
可以先行使用mychk_str_date()来检查,正确时再输入,不正确时就可以通知使用者.
PHP或是其他语言均可呼叫此MySQL函数,如同其他函数.

作者: bunko   发布时间: 2010-07-12

事实上可以简单一点....

就是将 mysql 的 sql-mode 设定为严格模式..

请参考这个连结里的资料...
http://dev.mysql.com/doc/refman/5.1/zh/database-administration.html#server-sql-mode
尤其关於 NO_ZERO_DATE , NO_ZERO_IN_DATE , ALLOW_INVALID_DATES 等...

会直接於遇到不合法的日期格式时候放弃该段 insert or update SQL

另外关於 MySQL 的 Date Time 相关的资讯建议阅读这个..
http://dev.mysql.com/doc/refman/5.1/zh/column-types.html#date-and-time-types

作者: Darkhero   发布时间: 2010-07-13

谢谢bunko兄和Darkhero兄的热心指导。
我先来好好的研究一下

作者: itw   发布时间: 2010-07-13