【问题标题】:Empty string in not-null column in MySQL?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

标签: php mysql mysqli nullable prepared-statement


【解决方案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。
        猜你喜欢
        • 2017-06-12
        • 2021-09-19
        • 2013-04-29
        • 2018-07-04
        • 1970-01-01
        • 2012-09-04
        • 1970-01-01
        • 1970-01-01
        • 2011-09-21
        相关资源
        最近更新 更多