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

发布于 2024-07-08 02:49:42 字数 1111 浏览 8 评论 0原文

我曾经使用标准 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违反了not-null constraint"

作为临时解决方法,我检查 $value 是否为空,并将其更改为 " " (单个空格),但这是一个可怕的黑客行为并可能导致其他问题。

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

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

请注意,“”和 NULL 不是同一件事。 例如,SELECT NULL = ""; 返回 NULL,而不是您期望的 1

I used to use the standard mysql_connect(), mysql_query(), etc statements for doing MySQL stuff from PHP. Lately I've been switching over to using the wonderful MDB2 class. Along with it, I'm using prepared statements, so I don't have to worry about escaping my input and SQL injection attacks.

However, there's one problem I'm running into. I have a table with a few VARCHAR columns, that are specified as not-null (that is, do not allow NULL values). Using the old MySQL PHP commands, I could do things like this without any problem:

INSERT INTO mytable SET somevarchar = '';

Now, however, if I have a query like:

INSERT INTO mytable SET somevarchar = ?;

And then in PHP I have:

$value = "";
$prepared = $db->prepare($query, array('text'));
$result = $prepared->execute($value);

This will throw the error "null value violates not-null constraint"

As a temporary workaround, I check if $value is empty, and change it to " " (a single space), but that's a horrible hack and might cause other issues.

How am I supposed to insert empty strings with prepared statements, without it trying to instead insert a NULL?

EDIT: It's too big of a project to go through my entire codebase, find everywhere that uses an empty string "" and change it to use NULL instead. What I need to know is why standard MySQL queries treat "" and NULL as two separate things (as I think is correct), but prepared statements converts "" into NULL.

Note that "" and NULL are not the same thing. For Example, SELECT NULL = ""; returns NULL instead of 1 as you'd expect.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(7

一向肩并 2024-07-15 02:49:42

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

  • 为什么空字符串在数据库中最终显示为 NULL? 为什么我得到 NULL
    NOT NULL 文本字段中不允许使用
    即使默认值是“”?

    • 问题是对于某些 RDBMS(尤其是 Oracle)来说,一个空的
      字符串为 NULL。 因此MDB2
      提供了一个可移植性选项
      对所有人强制执行相同的行为
      关系型数据库管理系统。
    • 由于所有可移植性选项均默认启用,因此您将拥有
      如果您不这样做,则禁用该功能
      想要有这种行为:
      $mdb2->setOption('可移植性',
      MDB2_PORTABILITY_ALL ^
      MDB2_PORTABILITY_EMPTY_TO_NULL);

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

Thanks to some of the answers, I realized that the problem may be in the MDB2 API, and not in the PHP or MYSQL commands themselves. Sure enough, I found this in the MDB2 FAQ:

  • Why do empty strings end up as NULL in the database? Why do I get an NULL
    not allowed in NOT NULL text fields
    eventhough the default value is ""?

    • The problem is that for some RDBMS (most noteably Oracle) an empty
      string is NULL. Therefore MDB2
      provides a portability option to
      enforce the same behaviour on all
      RDBMS.
    • Since all portability options are enabled by default you will have
      to disable the feature if you dont
      want to have this behaviour:
      $mdb2->setOption('portability',
      MDB2_PORTABILITY_ALL ^
      MDB2_PORTABILITY_EMPTY_TO_NULL);

Thanks to everyone who provided thoughtful answers.

病女 2024-07-15 02:49:42

这听起来像是 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 中找到(或实现)解决方法,则可能有一种黑客解决方案(尽管比您当前使用的解决方案稍好一些)为空字符串定义 用户变量 --

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

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

This sounds like a problem with the MDB2 API fumbling PHP's duck typing semantics. Because the empty string in PHP is equivalent to NULL, MDB2 is probably mis-treating it as such. The ideal solution would be to find a workaround for it within it's API, but I'm not overly familiar with it.

One thing that you should consider, though, is that an empty string in SQL is not a NULL value. You can insert them into rows declared 'NOT NULL' just fine:

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

If you're unable to find (or implement) a workaround in the MDB2 API, one hackish solution (though slightly better than the one you're currently using) might be to define a user variable for the empty string --

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

Finally, if you need to use the empty string in an INSERT statement but find yourself unable to, the default value for string types in MySQL is an empty string. So you could simply omit the column from INSERT statement and it would automatically get set to the empty string (provided the column has a NOT NULL constraint).

澜川若宁 2024-07-15 02:49:42

我意识到这个问题几乎已经得到解答并已退休,但我在寻找类似情况的答案时发现了它,并且我忍不住投身其中。

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

但是,空字符串(或空白,或空无一物,不仅仅是缺少任何东西(如 NULL))也可能只是意味着“NOT NULL”或“什么都没有,但仍然不为 Null”,您甚至可以走另一个方向。并建议缺少 NULL 值使其比 Null 更不重要,因为 Null 至少有一个可以大声说出的名称!

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

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

现在,如果有某种疯狂的机会,您实际上想要空字符串来表示甚至不值得 NULL 的内容,请再次为此提出一个更重要的符号,例如“-1”或“SUPERNULL”或“UGLIES”。

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

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

直到下次。

I realize this question is pretty much answered and retired, but I found it while looking for answers to a similar situation and I can't resist throwing my hat in the ring.

Without knowing what the NULL/"" column relates to, I can't know how the true significance of an empty string. Does empty string mean something unto itself (like, if I convinced a judge to let me change my name to simply nothing, I would be really irritated if my name showed up on my Driver's License as NULL. My name would be !

However, the empty string (or blank, or the nothingness that is SOMETHING, not simply the lack of anything (like NULL)) could also simply just mean "NOT NULL" or "Nothing, but still not Null". You could even go the other direction and suggest that the absence of the value NULL makes it even LESS something than Null, cuz at least Null has a name you can say aloud!

My point is, that if the empty string is a direct representation of some data (like a name, or what I prefer be inserted between the numbers in my phone number, etc), then your options are either to argue until you're sore for the legitimate use of empty string or to use something that represents an empty string that isn't NULL (Like an ASCII control character or some unicode equivalent, a regex value of some kind, or, even worse, an arbitrary yet totally unused token, like: ◘

If the empty cell really just means NOT NULL, then you could think of some other way of expressing it. One silly and obvious way is the phrase "Not NULL". But I have a hunch that NULL means something like "Not part of this group at all" while the empty string means something like "this guy is cool, he just hasn't gotten his gang tattoos yet". In which case I would come up with a term/name/idea for this situation, like "default" or "rookie" or "Pending".

Now, if by some crazy chance you actually want empty string to represent that which is not even worthy of NULL, again, come up with a more significant symbol for that, such as "-1" or "SUPERNULL" or "UGLIES".

In the Indian Caste System, the lowest Caste are Shudra: Farmers and Laborers. Beneath this caste are the Dalit: "The Untouchables". They are not considered a lower caste, because setting them as the lowest caste would be considered a contamination of the entire system.

So don't call me crazy for thinking empty strings may be WORSE than NULL!

'Til next time.

み青杉依旧 2024-07-15 02:49:42

我找到了解决方案!

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

I found the solution!

MDB2 converts empty strings to NULL because portability option MDB2_PORTABILITY_EMPTY_TO_NULL is on by default (thanks to Oracle which considers empty strings to be null).

Switch this options off when you connect to the database:

$options = array(
    'portability' => MDB2_PORTABILITY_ALL ^ MDB2_PORTABILITY_EMPTY_TO_NULL
);
$res= & MDB2::connect("mysql://user:password@server/dbase", $options);
苦行僧 2024-07-15 02:49:42

0 和空字符串都是变量,NULL 表示没有数据。 要容易得多:/

相信我,编写一个查询来SELECT * from table where Mything IS NULL 比尝试查询空字符串

While 0 and empty strings are variables NULL is the absence of data. And trust me, it's a lot easier to write a query to

SELECT * from table where mything IS NULL than to try to query for empty strings :/

影子的影子 2024-07-15 02:49:42

空引号 "" 不可以做到这一点吗?

Doesn't an empty set of quotes, "" do that?

墨离汐 2024-07-15 02:49:42

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

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

I'm confused. It looks like you're using mysqli OO (from the tags and style), but the syntax is different than the manual on php.net, which says to do this instead:

$query = "INSERT INTO mytable SET somevarchar = ?";
$value = "";
$prepared = $db->prepare($query);
$prepared->bind_param("s", $value);
$result = $prepared->execute();
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文