Mysql 5 : Tri sur nombres négatifs

WRInaute passionné
Bonjour,

J'ai un petit problème sur une requête de tri.

Elle doit trier un résultat d'un petit calcul sur deux colonnes.

ORDER BY (colonne1 * 5 - colonne2 * 3) DESC

Ces deux colonnes sont de type UNSIGNED.
Problème, il considère les nombres négatifs comme supérieurs...

Avec mysql 4, cela fonctionnait sans problème. Avez-vous une solution svp ? Merci.
 
WRInaute accro
Robinson a dit:
J'ai un petit problème sur une requête de tri.

Elle doit trier un résultat d'un petit calcul sur deux colonnes.

ORDER BY (colonne1 * 5 - colonne2 * 3) DESC

Ces deux colonnes sont de type UNSIGNED.
Problème, il considère les nombres négatifs comme supérieurs...

Avec mysql 4, cela fonctionnait sans problème. Avez-vous une solution svp ? Merci.

Au moins solutions:
- convertir en signed d'abord (cast(colonne1 as signed)..)
- ajouter une grande valeur (supérieure à la valeur absolue de la différence la plus petite) *avant* de soustraire, pour que le résultat reste positif (par exemple 10000 + colonne1*5 - colonne2*3)

Il doit y en avoir d'autres...

Jacques.
 
WRInaute accro
FlorentP a dit:
Ou reporter le bug a mysql :d

Je ne vois pas où est le bug, si on travaille avec des entiers non signés, et que le résultat d'une opération est négatif, forcément ça donne des choses pas très prévisibles, rien de plus normal.

Jacques.
 
WRInaute passionné
ecocentric a dit:
idée bête: tu as essayé de mettre un alias dans le SELECT et d'utiliser l'alias dans l'ORDER BY ?
Oui et c'est la même chose.

jcaron, pourquoi cela fonctionnait dans les versions mysql précédentes ?
Pas besoin de me répondre, je pense avoir une idée, comme php, les deux se veulent de plus en plus professionnels et donc de plus en plus tatillons et respectueux des normes de développement ^^
 
WRInaute discret
jcaron a dit:
FlorentP a dit:
Ou reporter le bug a mysql :d

Je ne vois pas où est le bug, si on travaille avec des entiers non signés, et que le résultat d'une opération est négatif, forcément ça donne des choses pas très prévisibles, rien de plus normal.

Jacques.
Ce n'est pas parceque les chiffres qu'il manipule sont non signés que le résultat doit l'être...
C'est comme si tu disais que mysql devait te retourner un résultat entre 0 et 255 si on faisait des opérations à partir d'un tinyint. Un tinyint multiplié par un autre, ya pas de raison qu'il reste borné dans un tinyint. Idem pour des opérations avec des unsigned.
 
WRInaute accro
FlorentP a dit:
Ce n'est pas parceque les chiffres qu'il manipule sont non signés que le résultat doit l'être...

Dans tous les langages que je connais, y compris SQL, le résultat d'une opération sur deux valeurs d'un type X est presque systématiquement (voire même tout le temps?) dans le même type X. C'est totalement volontaire, et ce n'est pas un bug, même s'il y a au moins un bug report par mois (refermé aussi vite) comme quoi postgresql est buggé parce qu'il dit que (par exemple) 1 / 2 * 2 = 0. Si tu veux obtenir le "bon" résultat, il faut passer par des floats, mais tu ne veux pas non plus qu'il passe sur des floats pour un oui ou pour un non alors que toi tu voulais qu'il reste sur des entiers... C'est un choix arbitraire, mais c'est comme ça.

D'ailleurs visiblement, ils doivent considérer que le comportement précédent est un bug, et qu'ils l'ont corrigé, il y a un moyen d'avoir l'ancien comportement:

"Si vous rencontrez un problème avec les colonnes UNSIGNED dans vos anciennes applications MySQL lorsque vous effectuez le port sous la version 4.0 de MySQL , vous pouvez utiliser l'option --sql-mode=NO_UNSIGNED_SUBTRACTION lorsque vous lancez mysqld. Notez cependant qu'aussi longtemps que vous employez ceci, vous ne serez pas capable d'utiliser efficacement les colonnes de type UNSIGNED BIGINT."

(from http://dev.mysql.com/doc/refman/5.0/fr/ ... tions.html)

FlorentP a dit:
C'est comme si tu disais que mysql devait te retourner un résultat entre 0 et 255 si on faisait des opérations à partir d'un tinyint. Un tinyint multiplié par un autre, ya pas de raison qu'il reste borné dans un tinyint. Idem pour des opérations avec des unsigned.

Je n'ai pas de serveur mysql sous la main, mais dans postgresql c'est nettement plus clair (mais smallint est sur 16 bits et pas 8 bits, et il n'y a pas de signed/unsigned):

Code:
# select 10000::smallint * 10000::smallint;
ERROR:  smallint out of range

# \do
                                                                              Liste des opérateurs
   Schéma   | Nom  |    Type de l'arg. gauche    |    Type de l'arg. droit     |      Type du résultat       |                           Description                            
------------+------+-----------------------------+-----------------------------+-----------------------------+------------------------------------------------------------------
[...]
 pg_catalog | *    | smallint                    | smallint                    | smallint                    | multiply

Jacques.
 
WRInaute discret
Bon apparement la solution au probleme c'est pas de reporter le changement de comportement a mysql mais de mettre l'option --sql-mode=NO_UNSIGNED_SUBTRACTION...

Pour ce qui est du résultat qui est toujours de type x sur une opération entre deux valeurs de type x : en C, si tu fais
printf("%d",r, unsigned int - unsigned int);
tu peux récupérer des valeures négatives sur ta valeure de retour.
Ce type de traitement doit être assez spécifique à certains langages, et je trouve pas ça super logique que ça fonctionne comme ça par défaut
 
WRInaute accro
FlorentP a dit:
Pour ce qui est du résultat qui est toujours de type x sur une opération entre deux valeurs de type x : en C, si tu fais
printf("%d",r, unsigned int - unsigned int);
tu peux récupérer des valeures négatives sur ta valeure de retour.

Parce que %d indique que la valeur est à condidérer comme un signed int. Tu devrais normalement utiliser %u (comme au final la représentation binaire reste la même, et que C ne fait pas d'erreur en cas d'overflow, tu retombes sur tes pattes).

Essaie plutôt ça:

Code:
unsigned a,b;
a=10;
b=20
if (a-b < 0)
{
         printf("negatif\n");
}
else
{
        printf("positif\n");
}

FlorentP a dit:
Ce type de traitement doit être assez spécifique à certains langages, et je trouve pas ça super logique que ça fonctionne comme ça par défaut

C'est comme ça en C comme en SQL. Je pense que c'est vrai dans beaucoup de langages fortement typés...

Jacques.
 
WRInaute passionné
Oui, c'est ainsi dans plein de langages, je l'avais déjà vu il y a quelques années (peut-être bien avec Access ou en C, me souviens pu).

Mon ptit BTS commence à remonter à quelques années, me fait vieux :'(
Et cette rigueur de développement, je l'avais un peu zappée avec le php et mysql ^^
 
Discussions similaires
Haut