web-dev-qa-db-fra.com

mysql - citer des nombres ou pas?

Par exemple, je crée une base de données et une table à partir de cli et insère des données:

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

Maintenant, je peux le faire et ces exemples fonctionnent (donc - les citations n’affectent rien de ce qui semble):

SELECT * FROM test WHERE id = '9';
INSERT INTO test VALUES ('11', 'some string');

Donc - dans ces exemples, j'ai sélectionné une ligne par un string qui est actuellement stocké comme INT dans mysql, puis j'ai inséré un string dans une colonne qui est INT.

Je ne comprends pas vraiment pourquoi cela fonctionne comme cela fonctionne ici. Pourquoi est-il permis d'insérer une chaîne dans une colonne INT?

Puis-je insérer tous les types de données Mysql sous forme de chaînes?

Ce comportement est-il standard dans différents SGBDR?

merci!

45
Stann

MySQL ressemble beaucoup à PHP et convertira automatiquement les types de données le mieux possible. Puisque vous travaillez avec un champ int (côté gauche), il va également essayer de convertir de manière transparente le côté droit de l'argument en un entier, donc '9' devient simplement 9.

Strictement parlant, les guillemets ne sont pas nécessaires et obligent MySQL à effectuer une conversion/conversion de typage, ce qui gaspille un peu de temps CPU. En pratique, sauf si vous exécutez une opération de la taille de Google, cette surcharge de conversion sera réduite au microscope.

60
Marc B

Vous ne devriez jamais mettre de guillemets autour de chiffres. Il y a une raison valable à cela.

Le vrai problème se résume au typage. Lorsque vous mettez des nombres entre guillemets, il est traité comme une chaîne et MySQL doit le convertir en nombre avant de pouvoir exécuter la requête. Bien que cela puisse prendre un peu de temps, les vrais problèmes commencent à se poser lorsque MySQL ne convertit pas correctement votre chaîne. Par exemple, MySQL convertira les chaînes de base comme "123" en entier 123, mais convertira des nombres plus grands, comme "18015376320243459", en virgule flottante. La virgule flottante pouvant être arrondie, vos requêtes peuvent renvoyer des résultats incohérents. En savoir plus sur le transtypage ici . Selon le matériel et le logiciel de votre serveur, ces résultats peuvent varier. MySQL explique cela.

Si vous êtes inquiet à propos des injections SQL, vérifiez toujours la valeur en premier et utilisez PHP pour éliminer les nombres non nuls. Vous pouvez utiliser preg_replace pour cela: preg_replace("/[^0-9]/", "", $string)

De plus, si vous écrivez vos requêtes SQL avec des guillemets, elles ne fonctionneront pas sur des bases de données telles que PostgreSQL ou Oracle.

8
Sean

Vérifiez cela, vous pouvez mieux comprendre ...

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)
3
Srinivas Kishore

Ce n'est pas un comportement standard.

Pour MySQL 5.5. c'est le mode SQL par défaut

mysql> select @@sql_mode;
+------------+
| @@sql_mode |
+------------+
|            |
+------------+
1 row in set (0.00 sec)

ANSI et TRADITIONAL sont utilisés de manière plus rigoureuse par Oracle et PostgreSQL. Les modes SQL autorisés par MySQL doivent être définisSI ET SEULEMENT SI vous souhaitez que le code SQL soit davantage conforme à la norme ANSI. Sinon, vous ne devez rien toucher. Je ne l'ai jamais fait.

3
RolandoMySQLDBA

Autant que je sache, c’est standard, mais c’est considéré comme une mauvaise pratique parce que
- l’utiliser dans une clause WHERE empêchera l’optimiseur d’utiliser des index (le plan d’explication devrait montrer que)
- la base de données doit faire un travail supplémentaire pour convertir la chaîne en un nombre
- si vous utilisez ceci pour les nombres à virgule flottante ('9.4'), vous rencontrerez des problèmes si le client et le serveur utilisent des paramètres de langue différents (9.4 vs 9,4)

En bref: ne le faites pas (mais YMMV)

3
Frank Schmitt

Vous n'avez pas besoin de citer les chiffres, mais c'est toujours une bonne habitude si vous faites comme si c'était cohérent.

1
Anush

Cela dépend du type de colonne! Si vous exécutez 

SELECT * FROM `users` WHERE `username` = 0;

dans mysql/maria-db, vous obtiendrez tous les enregistrements où username IS NOT NULL.

Citez toujours les valeurs si la colonne est de type chaîne (char, varchar, ...) sinon vous obtiendrez des résultats inattendus!

0
pine3ree

Le problème est, disons que nous avons une table appelée utilisateurs, qui a une colonne appelée current_balance de type FLOAT, si vous exécutez cette requête:

UPDATE `users` SET `current_balance`='231608.09' WHERE `user_id`=9;

Le champ current_balance sera mis à jour en 231608, car MySQL a arrondi les limites, de la même manière si vous essayez cette requête:

UPDATE `users` SET `current_balance`='231608.55' WHERE `user_id`=9;

Le champ current_balance sera mis à jour à 231609

0
Tamer