为什么文本列在MySQL中不能具有默认值?


184

如果尝试在表上创建TEXT列,并在MySQL中为其提供默认值,则会收到错误消息(至少在Windows上如此)。我看不到任何原因为何文本列不应具有默认值。MySQL文档未给出任何解释。对我来说似乎不合逻辑(并且有些沮丧,因为我想要一个默认值!)。有人知道为什么不允许这样做吗?


1
我们可以看到您使用的查询吗?
罗伯特2010年

2
您确定要TEXT列而不是VARCHAR列吗?TEXT列用于长度可能超过255个字节的事物。
scy 2010年

5
这应该是一条评论。而且,是的,他的意思是TEXT-这些列不能具有默认值。VARCHAR能够。
Pekka

1
如果您使用phpmyadmin来设置数据库,则可能要研究mysql gui工具/工作台...;)
dmp 2010年

1
是的,不幸的是我需要超过255个字符。
罗斯,2010年

Answers:


92

Windows MySQL v5引发错误,但Linux和其他版本仅引发警告。这需要解决。 WTF?

另请参见尝试将其修复为MySQL Bugtracker中的错误#19498:

布莱斯·内斯比特(Bryce Nesbitt),2008年4月4日4:36 pm:
在MS Windows上,“ no DEFAULT”规则是错误,而在其他平台上,这通常是警告。虽然不是错误,但是如果您在宽松的平台上编写代码,然后在严格的平台上运行它,则可能会陷入此陷阱:

就个人而言,我确实将此视为错误。搜索“ BLOB / TEXT列不能具有默认值”在Google上返回大约2,940个结果。它们中的大多数是关于尝试安装在一个系统上有效但在其他系统上无法正常工作的DB脚本不兼容的报告。

现在,我正在为一个客户端(最初部署在Linux MySQL v5.0.83-log上)修改的Web应用程序上遇到相同的问题。我正在运行Windows MySQL v5.1.41。即使尝试使用最新版本的phpMyAdmin提取数据库,它也不会报告有关文本列的默认值。但是,当我尝试在Windows上运行插入(在Linux部署上可以正常工作)时,我在ABC列上收到没有默认错误。我尝试使用明显的默认值(基于该列的唯一值的选择)在本地重新创建表,并最终收到非常有用的BLOB / TEXT列不能具有默认值

同样,不保持跨平台的基本兼容性是不可接受的,并且是一个错误。


如何在MySQL 5(Windows)中禁用严格模式:

  • 编辑/my.ini并查找行

    sql-mode="STRICT_TRANS_TABLES,NO_AUTO_CREATE_USER,NO_ENGINE_SUBSTITUTION"
  • 替换为

    sql_mode='MYSQL40'
  • 重新启动MySQL服务(假设它是mysql5)

    net stop mysql5
    net start mysql5

如果您具有root / admin访问权限,则可以执行

mysql_query("SET @@global.sql_mode='MYSQL40'");

3
如果您具有root用户访问权限并且正在使用phpMyAdmin,请转到主页(单击phpMyAdmin徽标),转到“变量”选项卡,找到sql_mode变量,然后单击“编辑”。
加文

1
我正在使用CentOS 5.8和MySQL v 14.14 Distrib 5.1.71尝试将默认值设置为TEXT字段时抛出错误而不是警告。只是要注意,它不适用于每个Linux平台。
Alex

这些天来,OS X似乎至少会引发错误。docs dev.mysql.com/doc/refman/5.7/en/blob.html说“ BLOB和TEXT列不能具有DEFAULT值”。FWIW(但不是为什么)
rogerdpack '16

31

没有对mySQL引擎的深入了解,我想这听起来像是一种内存节省策略。我认为原因是来自文档的本段:

每个BLOB或TEXT值在内部都由单独分配的对象表示。这与所有其他数据类型形成对比,其他所有数据类型在打开表时为每列分配一次存储。

似乎预填充这些列类型将导致内存使用和性能下降。


5
-1:与在CHAR或VARCHAR列中存储相同的数据相比,在TEXT列中存储数据(例如城市名称)实际上需要的总内存更少。
大卫·卡里

5
@david我引用的手册章节不是关于存储,而是关于检索。
Pekka 2012年

1
我不认为这将导致任何异常的内存使用和性能损失。显然,当用户定义默认值时,无论数据类型是什么(特别是在批量操作上),他都希望性能受到影响。但是据我所知,您指出对于BLOB / TEXT字段,与其他数据类型相比,此性能命中率相对较高吗?这与BLOB / TEXT在内部存储为独立对象的事实有何关系?这对我来说毫无意义。
2014年

27
恕我直言,这不是节省内存的策略。这是一个错误,还是写它的人都疯了。我认为是后者,因为他们现在至少有8年无法修复。其他所有数据库都具有的基本功能。
2014年

2
没关系,它仍然是想要使用它的人的选择。
jurchiks 2015年

15

通过使用触发器,您可以获得与默认值相同的效果

create table my_text

(
   abc text
);

delimiter //
create trigger mytext_trigger before insert on my_text
for each row
begin
   if (NEW.abc is null ) then
      set NEW.abc = 'default text';
   end if;
end
//
delimiter ;

14

作为主要问题:

有人知道为什么不允许这样做吗?

仍然没有答案,我进行了快速搜索,并在MySQL Bugs上从MySQL开发人员那里找到了一个相对较新的功能:

[2017年3月17日15:11]StåleDeraas

开发者发布:

这确实是一个有效的功能请求,乍看之下添加起来似乎微不足道。但是TEXT / BLOBS值并不直接存储在用于读取/更新表的记录缓冲区中。因此,为它们分配默认值会有点复杂。

这不是绝对的答案,至少是为什么问题的起点。

同时,我将围绕它进行编码,或者使该列可为空,或者''insert应用程序代码中的每个显式分配一个(默认)值。


13

“在TEXT / BLOB列中支持DEFAULT”是MySQL Bugtracker中的一项 功能请求(错误#21532)

我不是唯一想在TEXT列中输入默认值的人。我认为此功能应在更高版本的MySQL中得到支持。

这在MySQL 5.0版本中无法修复,因为如果有人试图在不支持该功能的(当前)数据库与任何支持该功能的数据库之间来回传输数据库,显然会导致不兼容和数据丢失。该功能。


在我看来,对于允许空值的TEXT列,您应该可以在“”和NULL之间进行更改。似乎不可能做到。
phpguru

6

我通常在Linux上运行站点,但是我也在本地Windows计算机上进行开发。我已经多次遇到此问题,并且在遇到问题时才修复表。我昨天安装了一个应用程序来帮助某人,当然又遇到了问题。因此,我认为是时候弄清楚发生了什么事情-找到了这个线程。我真的不喜欢将服务器的sql_mode更改为较早的模式(默认情况下)的想法,因此我想出了一个简单的(我认为)解决方案。

当然,此解决方案需要开发人员包装表创建脚本,以补偿Windows上运行的MySQL问题。您将在转储文件中看到类似的概念。BIG的一个警告是,如果使用分区,这可能/将引起问题。

// Store the current sql_mode
mysql_query("set @orig_mode = @@global.sql_mode");

// Set sql_mode to one that won't trigger errors...
mysql_query('set @@global.sql_mode = "MYSQL40"');

/**
 * Do table creations here...
 */

// Change it back to original sql_mode
mysql_query('set @@global.sql_mode = @orig_mode');

就是这样


1
这并没有解决为什么MySQL完全具有这种行为的问题,但是感谢您分享您的方法,以便其他人也可以从中受益。欢迎使用Stack Overflow!
GargantuChet 2012年

1
是的,我知道...我将不得不进一步研究STRICT模式,看看它是否有意义-因为MySQL在Nix的框上发出警告,但在Windows框上失败。这表明无论平台如何,实现都可能有问题。您会注意到,在MySQL文档中,有这样的通知:“ BLOB和TEXT列不能具有DEFAULT值。” 从逻辑上讲,似乎所​​有平台上的5之前版本的实现实际上都已中断。
Darrell Greenhouse'Sep

3

对于Ubuntu 16.04:

如何在MySQL 5.7中禁用严格模式:

编辑文件/etc/mysql/mysql.conf.d/mysqld.cnf

如果mysql.cnf中存在以下行

sql-mode="STRICT_TRANS_TABLES,NO_AUTO_CREATE_USER,NO_ENGINE_SUBSTITUTION"

然后将其替换为

sql_mode='MYSQL40'

除此以外

只需在mysqld.cnf中添加以下行

sql_mode='MYSQL40'

这个问题解决了。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.