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

Posted

技术标签:

【中文标题】MySQL中非空列中的空字符串?【英文标题】:Empty string in not-null column in MySQL? 【发布时间】:2010-09-20 22:53:26 【问题描述】:

我曾经使用标准的 mysql_connect()、mysql_query() 等语句从 php 中执行 MySQL 操作。最近我一直在转而使用美妙的 MDB2 类。除此之外,我还使用准备好的语句,所以我不必担心逃避输入和 SQL 注入攻击。

但是,我遇到了一个问题。我有一个包含几个 VARCHAR 列的表,这些列被指定为非空(即,不允许 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 是否为空,并将其更改为 " "(一个空格),但这是一个可怕的 hack,可能会导致其他问题。

我应该如何使用准备好的语句插入空字符串,而不是尝试插入 NULL?

编辑:这是一个太大的项目,无法遍历我的整个代码库,找到使用空字符串“”的所有地方并将其更改为使用 NULL。我需要知道的是为什么标准 MySQL 查询将“”和 NULL 视为两个独立的事物(我认为是正确的),但准备好的语句将“”转换为 NULL。

请注意,“”和 NULL 不是相同的东西。例如,SELECT NULL = ""; 返回 NULL 而不是您所期望的 1

【问题讨论】:

如果插入" ",基本为null,为什么不将db中的字段更改为允许null。 它“基本上为空”,就像 0“基本上”为假一样。它们很相似,但实际上完全不同。 NULL 表示“无值”不是,“空字符串” 这是真的,但是存储一个“空”,因为它不包含数据、值,我几乎肯定比存储一个 NULL 成本更高 你说 NULL 和 "" 不一样是对的,但是你不应该像 SELECT NULL = "";无论您将什么值与 null 进行比较,这些都将始终返回 null 【参考方案1】:

感谢一些答案,我意识到问题可能出在 MDB2 API 上,而不是 PHP 或 MYSQL 命令本身。果然,我在 MDB2 FAQ 中找到了这个:

为什么空字符串在数据库中最终为 NULL?为什么我得到一个 NULL 不允许在 NOT NULL 文本字段中 即使默认值为“”? 问题在于,对于某些 RDBMS(最值得注意的是 Oracle),一个空的 字符串为 NULL。因此 MDB2 提供了一个可移植选项 对所有人强制执行相同的行为 关系型数据库。 由于默认情况下启用了所有可移植性选项,因此您将拥有 如果您不禁用该功能 想要有这种行为: $mdb2->setOption('可移植性', MDB2_PORTABILITY_ALL ^ MDB2_PORTABILITY_EMPTY_TO_NULL);

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

【讨论】:

【参考方案2】:

这听起来像是 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 中找到(或实施)解决方法,则一种骇人听闻的解决方案(尽管比您当前使用的解决方案稍好)可能是为空字符串定义 user variable - -

SET @EMPTY_STRING = "";
UPDATE tbl SET row=@EMPTY_STRING;

最后,如果您需要在 INSERT 语句中使用空字符串,但发现自己无法使用,那么 MySQL 中字符串类型的默认值是空字符串。因此,您可以简单地从 INSERT 语句中省略该列,它会自动设置为空字符串(假设该列具有 NOT NULL 约束)。

【讨论】:

就是这样,没想到MDB2本身可能是罪魁祸首。谢谢。【参考方案3】:

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

在不知道 NULL/"" 列与什么相关的情况下,我无法知道空字符串的真正意义。空字符串本身是否意味着什么(比如,如果我说服法官让我将我的名字改成什么都没有,如果我的名字在我的驾照上显示为 NULL,我会非常恼火。我的名字会是!

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

我的意思是,如果空字符串是某些数据的直接表示(例如姓名,或者我更喜欢在电话号码中的数字之间插入什么等),那么您的选择是争论直到您'对于空字符串的合法使用或使用表示非 NULL 的空字符串(如 ASCII 控制字符或某些 unicode 等效项、某种正则表达式值,或者更糟糕的是,任意完全未使用的令牌,例如:◘

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

现在,如果你真的很想用空字符串来表示甚至不值得为 NULL 的内容,那么再次为此想出一个更重要的符号,例如“-1”或“SUPERNULL”或“丑陋”。

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

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

'直到下次。

【讨论】:

【参考方案4】:

我找到了解决办法!

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);

【讨论】:

嗯...我在一年前写了这个确切的答案。【参考方案5】:

虽然 0 和空字符串是变量,但 NULL 表示没有数据。相信我,向

编写查询要容易得多

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

【讨论】:

【参考方案6】:

难道没有一组空引号"" 这样做吗?

【讨论】:

不,"" 和 NULL 是不同的东西,在大多数数据库中表现不同。 @davr - 这正是我说这样做的原因 - 他试图将 NOT NULL 值放入数据库,其中空引号是【参考方案7】:

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

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

【讨论】:

我用的是MDB2,内部使用的是mysqli。

以上是关于MySQL中非空列中的空字符串?的主要内容,如果未能解决你的问题,请参考以下文章

MySQL,最好插入 NULL 或空字符串?

用 DataFrame 中的 None/null 值替换空字符串

mysql 数据类型

MySQL中如何排除null和空字符串的条件

MySql查询在Select中用空字符串替换NULL

MySQL数据类型