MySQL中非空列中的空字符串?

Empty string in not-null column in MySQL?

提问人:davr 提问时间:11/6/2008 最后编辑:Scott Weldondavr 更新时间:6/6/2015 访问量:40963

问:

我曾经使用标准的 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 = "";NULL1

php mysql mysqli 可为 null 的准备语句

评论

1赞 UnkwnTech 11/6/2008
如果要插入 “ ”(基本上是 null),为什么不将 db 中的字段更改为允许 null。
6赞 nickf 11/6/2008
它“基本上是空的”,就像 0 是“基本上”假的一样。它们很相似,但实际上完全不同。
1赞 warren 11/6/2008
NULL 表示“无值”而不是“空字符串”
1赞 UnkwnTech 11/6/2008
这是真的,但存储一个“空”,因为它不包含数据、值,我几乎是正的,比存储一个 NULL 的成本更高
2赞 Tom Haigh 11/6/2008
你是对的,NULL 与 “” 不同,但你不应该做像 SELECT NULL = “”;无论您将什么值与 null 进行比较,它们都将始终返回 null

答:

0赞 warren 11/6/2008 #1

不是空的引号集吗?""

评论

0赞 davr 11/6/2008
不,“”和 NULL 是不同的东西,在大多数数据库中的行为不同。
0赞 warren 11/6/2008
@davr - 这正是我说这样做的原因 - 他试图将一个 NOT NULL 值放入 db,空引号是
-1赞 Powerlord 11/6/2008 #2

我很困惑。看起来您正在使用 mysqli OO(从标签和样式来看),但语法与 php.net 上的手册不同,后者说要这样做:

$query = "INSERT INTO mytable SET somevarchar = ?";
$value = "";
$prepared = $db->prepare($query);
$prepared->bind_param("s", $value);
$result = $prepared->execute();

评论

0赞 davr 11/6/2008
我正在使用 MDB2,它在内部使用 mysqli。
14赞 hark 11/6/2008 #3

这听起来像是 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 约束)。

评论

0赞 davr 11/6/2008
就是这样,我不认为 MDB2 本身可能是罪魁祸首。谢谢。
18赞 davr 11/6/2008 #4

多亏了一些答案,我意识到问题可能出在 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);

感谢所有提供周到答案的人。

1赞 Anthony 6/19/2009 #5

我意识到这个问题已经得到了很好的回答并退休了,但我在寻找类似情况的答案时发现了它,我忍不住把帽子扔进了擂台。

在不知道 NULL/“” 列与什么相关的情况下,我无法知道空字符串的真正意义。空字符串本身是否意味着什么(例如,如果我说服法官让我将我的名字更改为无,如果我的名字在我的驾驶执照上显示为 NULL,我会非常生气。我的名字是!

然而,空字符串(或空白,或虚无是某物,而不仅仅是缺少任何东西(如 NULL))也可能只是表示“NOT NULL”或“Nothing,但仍然不是 Null”。你甚至可以走到另一个方向,建议没有值 NULL 使它比 Null 更少,因为至少 Null 有一个你可以大声说出的名字!

我的观点是,如果空字符串是某些数据的直接表示(例如名称,或者我更喜欢插入在电话号码中的数字之间等),那么您的选择要么是争论,直到您为合法使用空字符串而感到痛苦,要么使用表示非 NULL 的空字符串的东西(例如 ASCII 控制字符或一些 unicode 等效字符, 某种正则表达式值,或者更糟糕的是,一个任意但完全未使用的标记,例如:◘

如果空单元格真的只是表示 NOT NULL,那么你可以想出一些其他的表达方式。一种愚蠢而明显的方式是短语“Not NULL”。但我有一种预感,NULL 的意思是“根本不属于这个群体”,而空字符串的意思是“这家伙很酷,他只是还没有纹上他的帮派纹身”。在这种情况下,我会为这种情况想出一个术语/名称/想法,例如“默认”或“新秀”或“待定”。

现在,如果出于某种疯狂的机会,你真的希望空字符串来表示甚至不值得 NULL 的东西,那么再次,想出一个更重要的符号,例如“-1”或“SUPERNULL”或“UGLIES”。

在印度种姓制度中,最低的种姓是首陀罗:农民和劳工。在这个种姓之下是达利特人:“贱民”。他们不被视为低种姓,因为将他们定为最低种姓将被视为对整个系统的污染。

所以不要因为认为空字符串可能比 NULL 更糟糕而称我为疯子!

“下次再见。

1赞 ahhon 2/19/2010 #6

我找到了解决方案!

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赞 davr 2/20/2010
呃......我在一年多前写了这个确切的答案。
1赞 Lisa Simpson 6/1/2011 #7

虽然 0 和空字符串是变量,但 NULL 是缺少数据。相信我,编写查询要容易得多

SELECT * from table where mything IS NULL比尝试查询空字符串:/