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

时间:2008-11-05 20:03:48

标签: php mysql mysqli nullable prepared-statement

我曾经使用标准的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,正如您所期望的那样。

7 个答案:

答案 0 :(得分:17)

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

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

感谢所有提供深思熟虑答案的人。

答案 1 :(得分:12)

这听起来像是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解决方案(虽然略好于您当前使用的解决方案)可能是为空定义user variable字符串 -

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

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

答案 2 :(得分:2)

我意识到这个问题已得到很好的回答和退休,但我在寻找类似情况的答案时找到了它,我无法抗拒将我的帽子戴在戒指上。

在不知道NULL /“”列的相关内容的情况下,我无法知道空字符串的真正意义。空字符串本身就意味着什么(就像,如果我说服一位法官让我改变我的名字,我会真的很恼火,如果我的名字出现在我的驾驶执照上为NULL。我的名字就是!

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

我的观点是,如果空字符串是某些数据的直接表示(如姓名,或者我喜欢插入电话号码中的数字之间等),那么您的选择要么是争论直到你'对于合法使用空字符串感到痛苦,或者使用表示非空字符串的东西(就像ASCII控制字符或某些unicode等价物,某种类型的正则表达式值,或者更糟糕的是,是一种任意的完全未使用的令牌,如:◘

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

现在,如果有一些疯狂的机会你真的希望空字符串代表那些甚至不值得为NULL的字符串,那么再次提出一个更重要的符号,例如“-1”或“SUPERNULL”或“ UGLIES”。

在印度种姓制度中,最低的种姓是Shudra:农民和劳动者。在这个种姓之下是达利特:“不可触犯”。它们不被视为较低种姓,因为将它们设置为最低种姓将被视为整个系统的污染。

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

'下一次。

答案 3 :(得分:1)

我找到了解决方案!

MDB2将空字符串转换为NULL,因为默认情况下可移植性选项MDB2_PORTABILITY_EMPTY_TO_NULL处于打开状态(感谢Oracle认为空字符串为空)。

连接数据库时关闭此选项:

$options = array(
    'portability' => MDB2_PORTABILITY_ALL ^ MDB2_PORTABILITY_EMPTY_TO_NULL
);
$res= & MDB2::connect("mysql://user:password@server/dbase", $options);

答案 4 :(得分:1)

当0和空字符串是变量时,NULL是缺少数据。相信我,将查询写入

要容易得多

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

答案 5 :(得分:0)

不是一组空的引号""吗?

答案 6 :(得分:-1)

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

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