2008-12-04 8 views
1

Je reseting une colonne de tri qui a dupliquer ou les valeurs manquantes comme ceci:mysql se comporte différemment selon si une variable d'utilisateur existe

set @last=''; 
set @sort=NULL; 
update conf_profile set sort= 
    if(
     @last=(@last:=concat(org_id,',',profile_type_id,',',page,',',col)), 
     (@sort:[email protected]+1), 
     (@sort:=0) 
    ) 
order by org_id,profile_type_id,page,col,sort,id; 

(Aller à travers toutes les lignes triées par un certain nombre de clés champs assignant progressivement valeurs incrémentée à trier, à chaque fois que l'un de ces champs modification, redémarrez à 0.)

il semble fonctionner que si la variable @Sort a été créé avant de faire la mise à jour (bien qu'il n'a pas d'importance à quoi il était destiné). Sans 'set @sort', toutes les valeurs de tri sont définies sur 0 ou NULL.

Des idées pourquoi ce serait ainsi? MySQL version 5.0.51.

Mise à jour: Pour expliquer la logique plus longuement: sur la première rangée, le @last = (@ last: = ...) sera toujours faux, et par la suite il sera faux lorsque l'un des champs clés modifie de la rangée précédente. (N.B. aucun des champs clés étant concat'd sont jamais NULL). Lorsque c'est faux, nous recommençons le tri à 0 (@sort: = 0), sinon, il est incrémenté (@sort: = @ sort + 1) et la nouvelle valeur est utilisée.

En aucun cas, @sort n'est utilisé avant d'être défini dans l'instruction update, donc si ou comment il est défini avant l'instruction de mise à jour ne devrait faire aucune différence.

+0

Je sais que c'est une vieille question, mais le "En règle générale, vous ne devriez jamais attribuer une valeur à une variable utilisateur et lire la valeur dans la même déclaration." "Paragraphe de [Variables définies par l'utilisateur ] (http://dev.mysql.com/doc/refman/5.5/fr/user-variables.html) les docs le couvrent?En d'autres termes, MySQL peut choisir de faire quelque chose de complètement inattendu ... – Mike

+0

Je ne sais pas; il continue à montrer des cas de violation de cette règle générale et explique comment vous pouvez vous attendre à ce qu'ils travaillent, et mon cas n'en est pas un. Merci pour le lien, cependant. – ysth

Répondre

3

Une variable utilisateur non définie est traitée comme NULL si vous la référencez dans une expression. En SQL, NULL + 1 renvoie NULL. Si vous ne définissez pas @sort sur une valeur non NULL avant cette UPDATE, il continuera à être NULL, peu importe le nombre de fois que vous évaluez @sort:[email protected]+1. Une fois que vous faites @sort:=0, alors il devrait s'incrémenter normalement.

Essayez ceci sans le faire dans un UPDATE:

mysql> set @sort := NULL; 
mysql> SELECT @sort; -- returns NULL 
mysql> set @sort := @sort + 1; 
mysql> SELECT @sort; -- returns NULL again 
mysql> set @sort := 0; 
mysql> set @sort := @sort + 1; 
mysql> SELECT @sort; -- returns 1 

Je suppose que c'est seulement une coïncidence que vous avez pas de doublons après la première fois que vous définissez @sort:=0.

modifier: Ce qui précède est vrai, mais comme vous le dites, il n'explique pas le comportement que vous voyez, car logiquement @sort devrait être garantie mis à 0 lors de l'évaluation de la première ligne.

Cependant, je remarque si je change l'ordre des termes dans l'expression IF(), tout cela fonctionne, même si @sort est unset que nous commençons:

set @last=''; 
-- set @sort=NULL; 
update conf_profile set sort= 
    if(
     @last!=(@last:=concat(org_id,',',profile_type_id,',',page,',',col)), 
     (@sort:=0), 
     (@sort:[email protected]+1) 
    ) 
order by org_id,profile_type_id,page,col,sort,id; 

Je ne sais pas si je comprends assez bien pour expliquer exactement pourquoi cela fonctionne, mais il y a des choses loufoques concernant l'évaluation des variables utilisateur. Voir ce blog pour beaucoup d'exemples et de détails sanglants: "Advanced MySQL user variable techniques".

+0

Désolé, cela n'explique pas pourquoi cela fonctionne avec set @ sort = NULL mais pas sans. – ysth

+0

Merci pour le lien du blog. – ysth

Questions connexes