Оператор обновления mysql ведет себя по-разному в зависимости от того, существует ли переменная пользователя - PullRequest
1 голос
/ 04 декабря 2008

Я сбрасываю столбец сортировки, в котором есть повторяющиеся или отсутствующие значения, например:

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

(просмотреть все строки, отсортированные по количеству ключевых полей, назначаемых постепенно увеличенные значения для сортировки; при изменении любого из этих полей перезапустите с 0.)

Кажется, что это работает, только если переменная @sort была создана перед обновлением (хотя это не имеет значения, что это было установлено). Без 'set @sort' все Значения сортировки имеют значение 0 или NULL.

Есть идеи, почему это так? MySQL версия 5.0.51.

Обновление: чтобы объяснить логику более подробно: в первом ряду @last = (@ last: = ...) всегда будет ложным, и после этого будет ложным, когда любое из ключевых полей изменяется из предыдущего ряда. (N.B. ни одно из ключевых полей, являющихся concat'd, никогда не NULL). Когда оно ложно, мы начинаем счетчик сортировки снова с 0 (@sort: = 0), в противном случае это увеличивается (@sort: = @ sort + 1) и используется новое значение.

Ни в коем случае @sort не используется до того, как он будет задан в операторе обновления, так что как он установлен перед оператором обновления, не должно иметь значения.

1 Ответ

3 голосов
/ 04 декабря 2008

Неустановленная пользовательская переменная обрабатывается как NULL, если вы ссылаетесь на нее в выражении.

В SQL NULL + 1 возвращает NULL. Если вы не установите для @sort значение, отличное от NULL, до этого UPDATE, тогда оно останется равным NULL независимо от того, сколько раз вы оцениваете @sort:=@sort+1. Как только вы сделаете @sort:=0, он должен нормально увеличиваться.

Попробуйте это, не делая этого в 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

Полагаю, это просто совпадение, что у вас нет дубликатов после того, как вы в первый раз установили @sort:=0.

edit: Вышеприведенное верно, но, как вы заметили, оно не объясняет поведение, которое вы видите, поскольку логически @sort должно быть гарантировано установлено равным 0 во время оценки первого строка.

Тем не менее, я замечаю, что если я изменю порядок терминов в выражении IF(), все будет работать, даже если @sort не установлено, когда мы начинаем:

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

Я не уверен, что понимаю это достаточно хорошо, чтобы объяснить, почему это работает, но есть некоторые причудливые вещи, касающиеся оценки пользовательских переменных. В этом блоге вы найдете множество примеров и подробностей: " Продвинутые методы пользовательских переменных MySQL ".

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...