提问人:davr 提问时间:11/6/2008 最后编辑:Scott Weldondavr 更新时间:6/6/2015 访问量:40963
MySQL中非空列中的空字符串?
Empty string in not-null column in MySQL?
问:
我曾经使用标准的 mysql_connect()、mysql_query() 等语句从 PHP 执行 MySQL 操作。最近我一直在切换到使用精彩的 MDB2 类。除此之外,我还使用了准备好的语句,因此我不必担心逃避输入和 SQL 注入攻击。
但是,我遇到了一个问题。我有一个包含几个 VARCHAR 列的表,这些列被指定为非 null(即不允许 NULL 值)。使用旧的MySQL PHP命令,我可以毫无问题地做这样的事情:
INSERT INTO mytable SET somevarchar = '';
但是,现在,如果我有这样的查询:
INSERT INTO mytable SET somevarchar = ?;
然后在PHP中,我有:
$value = "";
$prepared = $db->prepare($query, array('text'));
$result = $prepared->execute($value);
这将抛出错误”null value violates not-null constraint
"
作为临时解决方法,我检查是否为空,并将其更改为(单个空格),但这是一个可怕的黑客,可能会导致其他问题。$value
" "
我应该如何插入带有准备好的语句的空字符串,而不尝试插入 NULL?
编辑:这是一个太大的项目,无法遍历我的整个代码库,找到使用空字符串“”的任何地方,并将其更改为使用 NULL。我需要知道的是,为什么标准MySQL查询将“”和NULL视为两个独立的东西(我认为这是正确的),但是准备好的语句将“”转换为NULL。
请注意,“”和 NULL 不是一回事。例如,返回而不是您期望的。SELECT NULL = "";
NULL
1
答:
不是空的引号集吗?""
评论
我很困惑。看起来您正在使用 mysqli OO(从标签和样式来看),但语法与 php.net 上的手册不同,后者说要这样做:
$query = "INSERT INTO mytable SET somevarchar = ?";
$value = "";
$prepared = $db->prepare($query);
$prepared->bind_param("s", $value);
$result = $prepared->execute();
评论
这听起来像是 MDB2 API 摸索 PHP 的鸭子类型语义的问题。因为 PHP 中的空字符串等同于 NULL,所以 MDB2 可能错误地将其视为空字符串。理想的解决方案是在其 API 中找到解决方法,但我对它不太熟悉。
但是,您应该考虑的一件事是,SQL 中的空字符串不是 NULL 值。您可以将它们插入到声明为“NOT NULL”的行中:
mysql> CREATE TABLE tbl( row CHAR(128) NOT NULL );
Query OK, 0 rows affected (0.05 sec)
mysql> INSERT INTO tbl VALUES( 'not empty' ), ( '' );
Query OK, 2 rows affected (0.02 sec)
Records: 2 Duplicates: 0 Warnings: 0
mysql> SELECT row, row IS NULL FROM tbl;
+-----------+-------------+
| row | row IS NULL |
+-----------+-------------+
| not empty | 0 |
| | 0 |
+-----------+-------------+
2 rows in set (0.00 sec)
mysql> INSERT INTO tbl VALUES( NULL );
ERROR 1048 (23000): Column 'row' cannot be null
如果您无法在 MDB2 API 中找到(或实现)解决方法,一个 hackish 解决方案(尽管比您当前使用的解决方案略好)可能是为空字符串定义一个用户变量——
SET @EMPTY_STRING = "";
UPDATE tbl SET row=@EMPTY_STRING;
最后,如果您需要在INSERT语句中使用空字符串,但发现自己无法使用,则MySQL中字符串类型的默认值为空字符串。因此,您可以简单地从 INSERT 语句中省略该列,它会自动设置为空字符串(前提是该列具有 NOT NULL 约束)。
评论
多亏了一些答案,我意识到问题可能出在 MDB2 API 上,而不是 PHP 或 MYSQL 命令本身。果然,我在 MDB2 FAQ 中找到了这一点:
- 为什么空字符串在数据库中最终为 NULL?为什么我得到一个 NULL 不允许在 NOT NULL 文本字段中使用 即使默认值为“”?
- 问题是对于某些RDBMS(最值得注意的是Oracle),一个空的 string 的数据类型为 NULL。因此 MDB2 提供可移植性选项 对所有人强制执行相同的行为 RDBMS的。
- 由于默认情况下启用了所有可移植性选项,因此您将拥有 如果不禁用该功能,请禁用该功能 想要有这种行为: $mdb 2->setOption('可移植性', MDB2_PORTABILITY_ALL ^ MDB2_PORTABILITY_EMPTY_TO_NULL);
感谢所有提供周到答案的人。
我意识到这个问题已经得到了很好的回答并退休了,但我在寻找类似情况的答案时发现了它,我忍不住把帽子扔进了擂台。
在不知道 NULL/“” 列与什么相关的情况下,我无法知道空字符串的真正意义。空字符串本身是否意味着什么(例如,如果我说服法官让我将我的名字更改为无,如果我的名字在我的驾驶执照上显示为 NULL,我会非常生气。我的名字是!
然而,空字符串(或空白,或虚无是某物,而不仅仅是缺少任何东西(如 NULL))也可能只是表示“NOT NULL”或“Nothing,但仍然不是 Null”。你甚至可以走到另一个方向,建议没有值 NULL 使它比 Null 更少,因为至少 Null 有一个你可以大声说出的名字!
我的观点是,如果空字符串是某些数据的直接表示(例如名称,或者我更喜欢插入在电话号码中的数字之间等),那么您的选择要么是争论,直到您为合法使用空字符串而感到痛苦,要么使用表示非 NULL 的空字符串的东西(例如 ASCII 控制字符或一些 unicode 等效字符, 某种正则表达式值,或者更糟糕的是,一个任意但完全未使用的标记,例如:◘
如果空单元格真的只是表示 NOT NULL,那么你可以想出一些其他的表达方式。一种愚蠢而明显的方式是短语“Not NULL”。但我有一种预感,NULL 的意思是“根本不属于这个群体”,而空字符串的意思是“这家伙很酷,他只是还没有纹上他的帮派纹身”。在这种情况下,我会为这种情况想出一个术语/名称/想法,例如“默认”或“新秀”或“待定”。
现在,如果出于某种疯狂的机会,你真的希望空字符串来表示甚至不值得 NULL 的东西,那么再次,想出一个更重要的符号,例如“-1”或“SUPERNULL”或“UGLIES”。
在印度种姓制度中,最低的种姓是首陀罗:农民和劳工。在这个种姓之下是达利特人:“贱民”。他们不被视为低种姓,因为将他们定为最低种姓将被视为对整个系统的污染。
所以不要因为认为空字符串可能比 NULL 更糟糕而称我为疯子!
“下次再见。
我找到了解决方案!
MDB2 将空字符串转换为 NULL,因为可移植性选项 MDB2_PORTABILITY_EMPTY_TO_NULL 默认处于打开状态(感谢 Oracle 将空字符串视为 null)。
连接到数据库时关闭此选项:
$options = array(
'portability' => MDB2_PORTABILITY_ALL ^ MDB2_PORTABILITY_EMPTY_TO_NULL
);
$res= & MDB2::connect("mysql://user:password@server/dbase", $options);
评论
虽然 0 和空字符串是变量,但 NULL 是缺少数据。相信我,编写查询要容易得多
SELECT * from table where mything IS NULL
比尝试查询空字符串:/
评论