content - mysql show table columns
mysql-citar nĂºmeros o no? (7)
Por ejemplo, creo una base de datos y una tabla de cli e inserto algunos datos:
CREATE DATABASE testdb CHARACTER SET ''utf8'' COLLATE ''utf8_general_ci'';
USE testdb;
CREATE TABLE test (id INT, str VARCHAR(100)) TYPE=innodb CHARACTER SET ''utf8'' COLLATE ''utf8_general_ci'';
INSERT INTO test VALUES (9, ''some string'');
Ahora puedo hacer esto y estos ejemplos sí funcionan (entonces, las citas no afectan nada parece):
SELECT * FROM test WHERE id = ''9'';
INSERT INTO test VALUES (''11'', ''some string'');
Entonces, en estos ejemplos he seleccionado una fila por una cadena que en realidad se almacena como INT en mysql y luego inserté una cadena en una columna que es INT.
No entiendo por qué funciona así como funciona aquí. ¿Por qué se permite insertar cadena en una columna INT?
¿Puedo insertar todos los tipos de datos Mysql como cadenas?
¿Este comportamiento es estándar en diferentes RDBMS?
¡Gracias!
AFAIK es estándar, pero se considera una mala práctica porque
- usarlo en una cláusula WHERE evitará que el optimizador use índices (explique que el plan debe mostrar eso)
- la base de datos tiene que hacer un trabajo adicional para convertir la cadena en un número
- Si está usando esto para números de coma flotante (''9.4''), se encontrará con problemas si el cliente y el servidor usan configuraciones de idioma diferentes (9.4 vs 9.4)
En resumen: no lo hagas (pero YMMV)
El problema es, digamos que tenemos una tabla llamada users, que tiene una columna llamada current_balance de tipo FLOAT, si ejecuta esta consulta:
UPDATE `users` SET `current_balance`=''231608.09'' WHERE `user_id`=9;
El campo current_balance se actualizará a 231608, porque MySQL hizo un redondeo, de manera similar si intenta esta consulta:
UPDATE `users` SET `current_balance`=''231608.55'' WHERE `user_id`=9;
El campo current_balance se actualizará a 231609
Este no es un comportamiento estándar.
Para MySQL 5.5. este es el modo SQL predeterminado
mysql> select @@sql_mode;
+------------+
| @@sql_mode |
+------------+
| |
+------------+
1 row in set (0.00 sec)
ANSI y TRADITIONAL son utilizados más rigurosamente por Oracle y PostgreSQL. Los modos de SQL que MySQL permite deben configurarse SI Y SÓLO si desea que SQL sea más compatible con ANSI. De lo contrario, no tienes que tocar nada. Nunca lo hice.
Mira esto, puedes entender mejor ...
mysql> EXPLAIN SELECT COUNT(1) FROM test_no WHERE varchar_num=0000194701461220130201115347;
+----+-------------+------------------------+-------+-------------------+-------------------+---------+------+---------+--------------------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+------------------------+-------+-------------------+-------------------+---------+------+---------+--------------------------+
| 1 | SIMPLE | test_no | index | Uniq_idx_varchar_num | Uniq_idx_varchar_num | 63 | NULL | 3126240 | Using where; Using index |
+----+-------------+------------------------+-------+-------------------+-------------------+---------+------+---------+--------------------------+
1 row in set (0.00 sec)
mysql> EXPLAIN SELECT COUNT(1) FROM test_no WHERE varchar_num=''0000194701461220130201115347'';
+----+-------------+------------------------+-------+-------------------+-------------------+---------+-------+------+-------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+------------------------+-------+-------------------+-------------------+---------+-------+------+-------------+
| 1 | SIMPLE | test_no | const | Uniq_idx_varchar_num | Uniq_idx_varchar_num | 63 | const | 1 | Using index |
+----+-------------+------------------------+-------+-------------------+-------------------+---------+-------+------+-------------+
1 row in set (0.00 sec)
mysql>
mysql>
mysql> SELECT COUNT(1) FROM test_no WHERE varchar_num=0000194701461220130201115347;
+----------+
| COUNT(1) |
+----------+
| 1 |
+----------+
1 row in set, 1 warning (7.94 sec)
mysql> SELECT COUNT(1) FROM test_no WHERE varchar_num=''0000194701461220130201115347'';
+----------+
| COUNT(1) |
+----------+
| 1 |
+----------+
1 row in set (0.00 sec)
MySQL se parece mucho a PHP y convertirá automáticamente los tipos de datos lo mejor que pueda. Dado que está trabajando con un campo int (lado izquierdo), tratará de convertir de forma transparente el lado derecho del argumento en un int también, por lo que ''9''
convierte en 9
.
Estrictamente hablando, las comillas son innecesarias y obligan a MySQL a hacer una conversión / conversión de tipo, por lo que desperdicia un poco de tiempo de CPU. En la práctica, a menos que esté ejecutando una operación del tamaño de Google, dicha sobrecarga de conversión será microscópicamente pequeña.
No necesita citar los números, pero siempre es un buen hábito si lo hace, ya que es coherente.
Nunca deberías poner comillas alrededor de los números. Hay una razón válida para esto.
El problema real se reduce al tipo de casting. Cuando coloca números dentro de comillas, se trata como una cadena y MySQL debe convertirlo a un número antes de poder ejecutar la consulta. Si bien esto puede tomar una pequeña cantidad de tiempo, los problemas reales comienzan a ocurrir cuando MySQL no hace un buen trabajo al convertir su cadena. Por ejemplo, MySQL convertirá cadenas básicas como ''123'' al número entero 123, pero convertirá algunos números más grandes, como ''18015376320243459'', en coma flotante. Como el punto flotante se puede redondear, sus consultas pueden devolver resultados inconsistentes. Obtenga más información sobre el tipo de conversión aquí . Dependiendo del hardware y software de su servidor, estos resultados variarán. MySQL explica esto.
Si le preocupan las inyecciones de SQL, siempre verifique primero el valor y use PHP para eliminar los números que no sean. Puede usar preg_replace para esto: preg_replace("/[^0-9]/", "", $string)
Además, si escribe sus consultas SQL con comillas, no funcionarán en bases de datos como PostgreSQL u Oracle.