¿Por qué una columna de texto no puede tener un valor predeterminado en MySQL?

185

Si intenta crear una columna TEXTO en una tabla y le da un valor predeterminado en MySQL, obtendrá un error (al menos en Windows). No puedo ver ninguna razón por la cual una columna de texto no debe tener un valor predeterminado. La documentación de MySQL no proporciona ninguna explicación. Me parece ilógico (y algo frustrante, ¡ya que quiero un valor predeterminado!). Alguien sabe por qué esto no está permitido?

Russ
fuente
1
¿Podemos ver la consulta que utilizó?
Robert
2
¿Estás seguro de que quieres una columna TEXTO, no una columna VARCHAR? Las columnas TEXT son para cosas que pueden tener más de 255 bytes de longitud.
scy
55
Esto debería ser un comentario. Además, sí, quiere decir que TEXTesas columnas no pueden tener un valor predeterminado. VARCHARlata.
Pekka el
1
Si está utilizando phpmyadmin para configurar su base de datos, es posible que desee investigar las herramientas / banco de trabajo de mysql gui ...;)
dmp
1
Sí, desafortunadamente necesito más de 255 caracteres.
Russ

Respuestas:

92

Windows MySQL v5 arroja un error, pero Linux y otras versiones solo generan una advertencia. Esto necesita ser arreglado. WTF?

También vea un intento de arreglar esto como el error # 19498 en el MySQL Bugtracker:

Bryce Nesbitt el 4 de abril de 2008 4:36 pm:
En MS Windows, la regla "no DEFAULT" es un error, mientras que en otras plataformas a menudo es una advertencia. Si bien no es un error, es posible quedar atrapado por esto si escribe código en una plataforma indulgente y luego lo ejecuta en una plataforma estricta:

Personalmente, veo esto como un error. La búsqueda de "la columna BLOB / TEXT no puede tener un valor predeterminado" arroja unos 2.940 resultados en Google. La mayoría de ellos son informes de incompatibilidades al intentar instalar scripts de DB que funcionaron en un sistema pero no en otros.

Me encuentro con el mismo problema ahora en una aplicación web que estoy modificando para uno de mis clientes, originalmente implementado en Linux MySQL v5.0.83-log. Estoy ejecutando Windows MySQL v5.1.41. Incluso tratando de usar la última versión de phpMyAdmin para extraer la base de datos, no informa un valor predeterminado para la columna de texto en cuestión. Sin embargo, cuando intento ejecutar una inserción en Windows (que funciona bien en la implementación de Linux) recibo un error de no predeterminado en la columna ABC. Intento recrear la tabla localmente con el valor predeterminado obvio (basado en una selección de valores únicos para esa columna) y termino recibiendo la columna BLOB / TEXT tan útil que no puede tener un valor predeterminado .

Nuevamente, no mantener la compatibilidad básica entre plataformas es inaceptable y es un error.


Cómo deshabilitar el modo estricto en MySQL 5 (Windows):

  • Edite /my.ini y busque la línea

    sql-mode="STRICT_TRANS_TABLES,NO_AUTO_CREATE_USER,NO_ENGINE_SUBSTITUTION"
  • Reemplácelo con

    sql_mode='MYSQL40'
  • Reinicie el servicio MySQL (suponiendo que es mysql5)

    net stop mysql5
    net start mysql5

Si tiene acceso root / admin, es posible que pueda ejecutar

mysql_query("SET @@global.sql_mode='MYSQL40'");
Ku Logix
fuente
3
Si tiene acceso de root y está usando phpMyAdmin, vaya a la página principal (haga clic en el logotipo de phpMyAdmin), vaya a la pestaña Variables, busque la variable sql_mode y haga clic en Editar.
Gavin
1
Estoy en un CentOS 5.8 y MySQL v 14.14 Distrib 5.1.71 arroja un error en lugar de una advertencia al intentar establecer un valor predeterminado en un campo TEXTO. Solo me gustaría notar que no funciona en todas las plataformas Linux.
Alex
OS X al menos parece arrojar un error en estos días. Los documentos dev.mysql.com/doc/refman/5.7/en/blob.html dicen "Las columnas BLOB y TEXT no pueden tener valores POR DEFECTO". FWIW (pero no por qué)
rogerdpack
31

Sin ningún conocimiento profundo del motor mySQL, diría que esto suena como una estrategia de ahorro de memoria. Supongo que la razón está detrás de este párrafo de los documentos :

Cada valor BLOB o TEXT está representado internamente por un objeto asignado por separado. Esto contrasta con todos los demás tipos de datos, para los cuales el almacenamiento se asigna una vez por columna cuando se abre la tabla.

Parece que rellenar previamente estos tipos de columnas conduciría al uso de memoria y a penalizaciones de rendimiento.

Pekka
fuente
55
-1: El almacenamiento de datos, como los nombres de ciudades, en una columna TEXTO en realidad requiere menos memoria total que el almacenamiento de los mismos datos en una columna CHAR o VARCHAR.
David Cary
55
@david el capítulo del manual que estoy citando no se trata de almacenamiento, sino de recuperación.
Pekka
1
No veo cómo eso conduciría a un uso anormal de la memoria y penalizaciones de rendimiento. Obviamente, cuando un usuario define un valor predeterminado, espera un impacto en el rendimiento sin importar el tipo de datos (especialmente en operaciones masivas). Sin embargo, por lo que entiendo, ¿usted afirma que para un campo BLOB / TEXT este impacto de rendimiento es relativamente alto en comparación con otros tipos de datos? ¿Y cómo se relaciona eso con el hecho de que BLOB / TEXT se almacena internamente como un objeto separado? Esto no tiene ningún sentido para mí.
extraño
27
En mi humilde opinión, no es una estrategia de ahorro de memoria. Es un error o las personas que lo escribieron están locas. Y creo que es lo último, ya que no pueden arreglarlo durante al menos 8 años. La funcionalidad básica que tiene cualquier otra base de datos.
extraño
2
No importa, aún debería ser una opción para las personas que quieran usarlo.
jurchiks
15

Puede obtener el mismo efecto que un valor predeterminado utilizando un disparador

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 ;
Tim Child
fuente
14

Como la pregunta principal:

Alguien sabe por qué esto no está permitido?

todavía no se responde, hice una búsqueda rápida y encontré una adición relativamente nueva de un desarrollador de MySQL en MySQL Bugs :

[17 de marzo de 2017 15:11] Ståle Deraas

Publicado por el desarrollador:

Esta es una solicitud de función válida y, a primera vista, puede parecer trivial agregar. Pero los valores TEXT / BLOBS no se almacenan directamente en el búfer de registro utilizado para leer / actualizar tablas. Por lo tanto, es un poco más complejo asignarles valores predeterminados.

Esta no es una respuesta definitiva, sino al menos un punto de partida para la pregunta de por qué .

Mientras tanto, solo codificaré alrededor y haré que la columna sea anulable o asignaré explícitamente un valor (predeterminado '') para cada uno insertdesde el código de la aplicación ...

Marten Koetsier
fuente
13

"Soporte para DEFAULT en columnas TEXT / BLOB" es una solicitud de función en MySQL Bugtracker (Bug # 21532) .

Veo que no soy el único a quien le gustaría poner un valor predeterminado en una columna TEXTO. Creo que esta característica debería ser compatible con una versión posterior de MySQL.

Esto no se puede solucionar en la versión 5.0 de MySQL, porque aparentemente causaría incompatibilidad y daños si alguien intentara transferir una base de datos de ida y vuelta entre las bases de datos (actuales) que no admiten esa función y las bases de datos que sí admitieron esa característica

David Cary
fuente
Me parece que debería poder cambiarlo entre "" y NULL para una columna TEXT que permita nulo. No parece posible hacerlo.
phpguru
6

Normalmente ejecuto sitios en Linux, pero también desarrollo en una máquina local de Windows. Me he encontrado con este problema muchas veces y simplemente arreglé las tablas cuando encontré los problemas. Instalé una aplicación ayer para ayudar a alguien y, por supuesto, me encontré con el problema nuevamente. Entonces, decidí que era hora de descubrir qué estaba pasando, y encontré este hilo. Realmente no me gusta la idea de cambiar el sql_mode del servidor a un modo anterior (por defecto), así que se me ocurrió una solución simple (creo).

Por supuesto, esta solución requeriría que los desarrolladores envuelvan sus scripts de creación de tablas para compensar el problema de MySQL que se ejecuta en Windows. Verá conceptos similares en los archivos de volcado. Una gran advertencia es que esto podría / causará problemas si se usa la partición.

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

Eso es todo.

Invernadero Darrell
fuente
1
Esto no aborda la pregunta de por qué MySQL tiene el comportamiento en absoluto, pero gracias por compartir su enfoque para que otros también puedan beneficiarse. ¡Bienvenido a Stack Overflow!
GargantuChet
1
Ya lo sé ... Tendré que buscar más en el modo ESTRICTO para ver si tiene sentido, ya que MySQL lanza una advertencia en los cuadros de Nix, pero falla en los cuadros de Windows. Eso es una indicación de que algo podría estar mal con la implementación, independientemente de la plataforma. Notará que en la documentación de MySQL, hay este aviso: "Las columnas BLOB y TEXT no pueden tener valores POR DEFECTO". Entonces, lógicamente, parece que la implementación en versiones anteriores a la 5 realmente se rompió en todas las plataformas.
Darrell Greenhouse
3

Para Ubuntu 16.04:

Cómo deshabilitar el modo estricto en MySQL 5.7:

Editar archivo /etc/mysql/mysql.conf.d/mysqld.cnf

Si debajo de la línea existe en mysql.cnf

sql-mode="STRICT_TRANS_TABLES,NO_AUTO_CREATE_USER,NO_ENGINE_SUBSTITUTION"

Luego reemplácelo con

sql_mode='MYSQL40'

De otra manera

Simplemente agregue la siguiente línea en mysqld.cnf

sql_mode='MYSQL40'

Este problema resuelto.

Shiv Buyya
fuente