Модераторы: skyboy

Поиск:

Ответ в темуСоздание новой темы Создание опроса
> Смещение на единицу в ячейке с несколькими записям 
:(
    Опции темы
In0stRAnez
  Дата 7.9.2015, 17:25 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Шустрый
*


Профиль
Группа: Участник
Сообщений: 85
Регистрация: 30.3.2008

Репутация: нет
Всего: нет



Привет коллеги, может такая тема уже и поднималась, тогда извиняйте

Структурка

Код

CREATE TABLE `table` (
  `id` smallint(6) NOT NULL AUTO_INCREMENT,
  `sort` smallint(5) DEFAULT '1'
  UNIQUE KEY `id` (`id`)
) ENGINE=MyISAM AUTO_INCREMENT=36 DEFAULT CHARSET=utf8;


Код

INSERT INTO `table` VALUES ('1','5');
INSERT INTO `table` VALUES ('2','4');
INSERT INTO `table` VALUES ('3','3');
INSERT INTO `table` VALUES ('4','2');
INSERT INTO `table` VALUES ('5','1');
...


Код

UPDATE `table`
SET `sort` = CASE 
WHEN '5' THEN '1'
WHEN '4' THEN '2'
END
WHERE `sort` IN (5,4);


В таблице хранятся новости, при выводе они сортируются по полю sort, необходимо сделать так чтоб админ мог указывать положение новости указывая каждой новости положение от 1-5

Это сообщение отредактировал(а) In0stRAnez - 7.9.2015, 17:39
PM MAIL   Вверх
Akina
Дата 7.9.2015, 17:34 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Советчик
****


Профиль
Группа: Модератор
Сообщений: 20581
Регистрация: 8.4.2004
Где: Зеленоград

Репутация: 45
Всего: 454



Нет, непонятно.


--------------------
 О(б)суждение моих действий - в соответствующей теме, пожалуйста. Или в РМ. И высшая инстанция - Администрация форума.

PM MAIL WWW ICQ Jabber   Вверх
In0stRAnez
Дата 7.9.2015, 17:42 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Шустрый
*


Профиль
Группа: Участник
Сообщений: 85
Регистрация: 30.3.2008

Репутация: нет
Всего: нет



поправил
PM MAIL   Вверх
Akina
Дата 7.9.2015, 17:58 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Советчик
****


Профиль
Группа: Модератор
Сообщений: 20581
Регистрация: 8.4.2004
Где: Зеленоград

Репутация: 45
Всего: 454



Ну это понятно. А проблема-то в чём? В том, что админ неспособен раскидать цифры от 1 до 5 в 5 записей так, чтобы каждая цифирь присутствовала в списке строго 1 раз?
К тому же проблема-то как бы не SQL-ная. Это проблема интерфейса - подстраховать этого дятла (ещё лучше отобрать у него ручной ввод, но оставить 2 кнопки - поднять текущую запись вверх на 1 позицию и соответственно опустить её вниз на 1 позицию). А когда он всё сделает как надо - вот тогда и сгенерить запрос на изменение данных. А если хочется, чтобы каждое такое смещение приводило к выполнению запроса, устанавливающего текущее положение вещей - твой запрос почти правильный. Только он должен идентифицировать записи по их ID, а менять sort. Типа:
Код

UPDATE `table` t1, `table` t2
SET t1.sort = t2.sort, t2.sort = t1.sort
WHERE t1.id = 5 AND t2.id = 4
этот запрос меняет местами порядок записей с ID, равными 4 и 5.


--------------------
 О(б)суждение моих действий - в соответствующей теме, пожалуйста. Или в РМ. И высшая инстанция - Администрация форума.

PM MAIL WWW ICQ Jabber   Вверх
jsharp36
Дата 8.9.2015, 09:27 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 4
Регистрация: 8.10.2011

Репутация: нет
Всего: 1



А мне ничего не понятно. Вы, наверное, что-то одинаковое курите ))

Цитата

   Задача такая, есть таблица, из нее я вывожу 5 новостей сортируя по ячейке `sort` ASC, данные в это поле вводятся вручную админом с значениями в диапазоне от 1-5, тем самым указывая какая новость будет идти первой, соответственно на конкретной новости админ указывает 1, значит при update значение 5 должно опуститься на 1 (1=NEW,2=5,3=4,4=3,5=2)
   


Это вообще можно понять без связи с космосом? Если админ указывает конкретной записи 1, то почему значение 5 должно опустится на 1, а не конкретная запись?
(Я догадываюсь, что всё дело в том, что id и sort одинакового типа, а в предложении яснее лень было выражаться, где что под чем подразумевается).

Надо объяснять задания с т.з. бизнеса, а не реализации. Т.е. например: "админ хочет некоторую запись выводить первой, а у остальных порядок вывода не должен измениться". Такое задание?

И в вашем SQL есть что-то вроде ROW_NUMBER? А то я больше по SQL-SERVER

Этот ответ добавлен с нового Винграда - http://vingrad.com
PM MAIL   Вверх
jsharp36
Дата 8.9.2015, 09:37 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 4
Регистрация: 8.10.2011

Репутация: нет
Всего: 1



если просто новость поновее должна идти первой, то вообще не надо ничего делать, никаких апдейтов. Вставку в колонку сортировки делайте с инкрементом, т.е. чтобы значение увеличивалось.
А при выборке меняете условие сортировки на DESC. И профит. Не надо апдейтить каждое поле, не надо ничего смещать. Если только порядок специально админ не захочет менять

Этот ответ добавлен с нового Винграда - http://vingrad.com
PM MAIL   Вверх
Akina
Дата 8.9.2015, 10:58 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Советчик
****


Профиль
Группа: Модератор
Сообщений: 20581
Регистрация: 8.4.2004
Где: Зеленоград

Репутация: 45
Всего: 454



Цитата(jsharp36 @  8.9.2015,  10:27 Найти цитируемый пост)
Это вообще можно понять без связи с космосом?

Нет, нельзя. Но можно предположить. Особенно когда есть опыт по "разворачиванию" во вменяемый текст такого рода вопросов и приблизительное понимание, что обычно хотят сделать на такой структуре.
Механика же происходящего мне до сих пор непонятна.
Цитата(jsharp36 @  8.9.2015,  10:27 Найти цитируемый пост)
Надо объяснять задания с т.з. бизнеса, а не реализации. Т.е. например: "админ хочет некоторую запись выводить первой, а у остальных порядок вывода не должен измениться". Такое задание?

НУ собсно тот же случай. Ну вот как "у остальных порядок вывода не должен измениться", если он заведомо изменится у записи, которая была первой?


--------------------
 О(б)суждение моих действий - в соответствующей теме, пожалуйста. Или в РМ. И высшая инстанция - Администрация форума.

PM MAIL WWW ICQ Jabber   Вверх
jsharp36
Дата 8.9.2015, 11:25 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 4
Регистрация: 8.10.2011

Репутация: нет
Всего: 1



Цитата

    Ну вот как "у остальных порядок вывода не должен измениться", если он заведомо изменится у записи, которая была первой?
   

если я правильно понял и надо просто одну запись подвинуть вперед на первое место, а остальные "сместить", то смещение производится элементарно, арифметикой.

напишу на T-SQL, потому как не знаю, как у вас переменные заводятся:

Код

declare @first_id int = 3

update [table]
set [sort] = case when [id] = @first_id then 1
                  when [sort] < (select [sort] from [table] where id = @first_id) then [sort] + 1
                  else [sort]
             end


но вообще что-то наводит на мысль, что сама идея так делать довольно глупая. Нужно просто развернуть сортировку и ничего никогда не смещать. Не должна быть таблица топ новостей ограничена 5-ю записями. По правилам моделирования такой таблицы вообще быть не должно, т.к это не сущность. Просто надо колонку сортировки добавить в таблицу новостей, с инкрементом. А выборку делать с DESC и если надо 5 записей, то ограничить выборку

Этот ответ добавлен с нового Винграда - http://vingrad.com
PM MAIL   Вверх
Akina
Дата 8.9.2015, 12:08 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Советчик
****


Профиль
Группа: Модератор
Сообщений: 20581
Регистрация: 8.4.2004
Где: Зеленоград

Репутация: 45
Всего: 454



jsharp36, не, это была всего лишь демонстрация, что любой человек обязательно использует какие-то умолчания, которые для него очевидны - но не всегда очевидны остальным.

Цитата(jsharp36 @  8.9.2015,  12:25 Найти цитируемый пост)
напишу на T-SQL

Сомнительный текст. 
Во-первых, не факт, что в подзапросе разрешено обращение к обновляемой таблице. 
Во-вторых, на поле sort может быть unique constraint, и это может привести к ошибкам уникальности и не-обновлению. А если такого ограничения нет - то подзапрос может вернуть набор из нескольких записей.
В третьих, результат выполнения подзапроса - это набор записей, даже если там на выходе одна запись с одним полем. Не каждая СУБД это разрешает, некоторые требуют строго скалярного значения. Впрочем, можно вывернуться использованием WHERE EXISTS.


--------------------
 О(б)суждение моих действий - в соответствующей теме, пожалуйста. Или в РМ. И высшая инстанция - Администрация форума.

PM MAIL WWW ICQ Jabber   Вверх
jsharp36
Дата 8.9.2015, 12:49 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 4
Регистрация: 8.10.2011

Репутация: нет
Всего: 1



как сомнительный? В каких вселенных к обновляемой таблице нет доступа на чтение?

Запрос происходит в одной транзакции, никаких даже с уникальным констрейнтом ошибок не происходит.


если не нравится простой запрос, то можно по классике с джойнами написать:
Код


declare @first_id int = 3

update t
set [sort] = case when t.[sort] = s.[sort] then 1
                  when t.[sort] < s.[sort] then t.[sort] + 1
                  else t.[sort]
             end
from [table] as t
cross join (select [sort] from [table] where id = @first_id) s



Этот ответ добавлен с нового Винграда - http://vingrad.com
PM MAIL   Вверх
Akina
Дата 8.9.2015, 15:18 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Советчик
****


Профиль
Группа: Модератор
Сообщений: 20581
Регистрация: 8.4.2004
Где: Зеленоград

Репутация: 45
Всего: 454



Цитата(jsharp36 @  8.9.2015,  13:49 Найти цитируемый пост)
В каких вселенных к обновляемой таблице нет доступа на чтение?

Пальцы-то сожми...
Код

mysql> create table `table`
    -> ( id int,
    ->   sort int
    -> );
Query OK, 0 rows affected (1.84 sec)

mysql> insert into `table` (id, sort)
    -> select 1,5 union
    -> select 2,4 union
    -> select 3,3 union
    -> select 4,2 union
    -> select 5,1 ;
Query OK, 5 rows affected (0.39 sec)
Records: 5  Duplicates: 0  Warnings: 0

mysql> select * from `table`;
+------+------+
| id   | sort |
+------+------+
|    1 |    5 |
|    2 |    4 |
|    3 |    3 |
|    4 |    2 |
|    5 |    1 |
+------+------+
5 rows in set (0.03 sec)

mysql> select 3 into @first_id;
Query OK, 1 row affected (0.01 sec)

mysql> update `table`
    -> set `sort` = case when `id` = @first_id then 1
    ->                   when `sort` < (select `sort` from `table` where id = @first_id) then `sort` + 1
    ->                   else `sort`
    -> end;
ERROR 1093 (HY000): You can't specify target table 'table' for update in FROM clause
mysql>



--------------------
 О(б)суждение моих действий - в соответствующей теме, пожалуйста. Или в РМ. И высшая инстанция - Администрация форума.

PM MAIL WWW ICQ Jabber   Вверх
In0stRAnez
  Дата 8.9.2015, 15:39 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Шустрый
*


Профиль
Группа: Участник
Сообщений: 85
Регистрация: 30.3.2008

Репутация: нет
Всего: нет



Уточняю задачу, есть новости, админ хочет сам выставлять порядок отображения новостей в топе, но так как текучка новостей большая и выставлять он будет не так часто, необходимо сделать так чтоб когда админ указывал новой новости конкретную позицию (например позиция 4) то 5 позиция должна остаться неизменной, а 3 -ей станет новость которая была 4, и так далее соответственно!

Коллеги спасибо, за дисскусию
PM MAIL   Вверх
jsharp36
Дата 8.9.2015, 16:16 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 4
Регистрация: 8.10.2011

Репутация: нет
Всего: 1



ого. А второй запрос работает?

Так тут или крестик снять или трусы надеть. Если эта СУБД не позволяет в одной транзакции и читать и делать сложные вычисления (например, свалится по уникальным значениям не завершая еще запрос, т.е. не по окончанию выполнения запроса), то вы ничего и не сделаете особо умного: просто разбивайте запрос на части.

Сначала находите и запоминаете в переменную текущий sort, который надо переставить. А потом апдейт.
Если субд не поддерживает нормальных транзакций, да еще и разрешает делать unique key, то тут уже на свой риск придется писать запросы, вы никак не сможете "перестановку" сделать безопасно.
Ну например. Разбиваем запрос на два, чтобы разрулить то, что субд не умеет обращаться при апдейте к этой же таблице (я с MySQL не знаком):

Код

declare @first_id int = 3
declare @sort int

select @sort = [sort] from [table] where id = @first_id

update [table]
set [sort] = case when t.[sort] = @sort then 1
                  when t.[sort] < @sort then t.[sort] + 1
                  else t.[sort]
             end



Теперь всё, что возможно, мы сделали. Никаких обращений к таблице. Единственная, но очень печальная вещь: при одновременном выполнении нескольких запросов начнут случаться казусы. (возможно практически на это можно не обращать внимания, потому что админ скорее всего один и такого не будет).

Если же даже в течении работы одного запроса уникальность проверяется по ходу обновления таблицы, то еще печальнее. Вообще почти ничего сделать толкового нельзя, принципиально. Например, запрос можно рабить уже на 4:

Код

declare @first_id int = 3
declare @sort int

select @sort = [sort] from [table] where id = @first_id

update [table]
set [sort] = 0
where id = @first_id

update [table]
set [sort] = case when t.[sort] < @sort then t.[sort] + 1
                  else t.[sort]
             end

update [table]
set [sort] = 1
where id = @first_id



Но тут та же проблема: если кто-то одновременно попытается сделать то же самое, то может попытаться выставить в 0 то, когда 0 временно занят.

И ваш запрос:

Код

UPDATE `table` t1, `table` t2
SET t1.sort = t2.sort, t2.sort = t1.sort
WHERE t1.id = 5 AND t2.id = 4


так же свалится. В какой-то момент в таблице будет два одинаковых значения.

Для этого в общем-то и нужны транзакции и всё правильно и красиво разруливать. Если эти средства не реализованы или не достаточно хорошо реализованы, то ничего не остается, как разбивать запросы на куски и самому что-то выдумывать вместо транзакций.

Да, ниже автор описал задачу, я вынужден преклониться перед вашей проницательностью ))) 12 лет у меня серьезного опыта, а мысли читать еще не научился.

Этот ответ добавлен с нового Винграда - http://vingrad.com
PM MAIL   Вверх
jsharp36
Дата 8.9.2015, 18:11 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 4
Регистрация: 8.10.2011

Репутация: нет
Всего: 1



и кстати, вы по сути джойн и написали в своем запросе. Хотя это и не легальный для T-SQL синтаксис.

так что в MySQL аналогичный моему запрос будет таким (если ваш работает, то и этот должен):

Код

update `table` t, `table` s
set t.`sort` = case when t.`sort` = s.`sort` then 1
                    when t.`sort` < s.`sort` then t.`sort` + 1
                    else t.`sort`
               end
where s.`id` = 3;




Этот ответ добавлен с нового Винграда - http://vingrad.com
PM MAIL   Вверх
Akina
Дата 8.9.2015, 18:48 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Советчик
****


Профиль
Группа: Модератор
Сообщений: 20581
Регистрация: 8.4.2004
Где: Зеленоград

Репутация: 45
Всего: 454



Цитата(In0stRAnez @  8.9.2015,  16:39 Найти цитируемый пост)
необходимо сделать так чтоб когда админ указывал новой новости конкретную позицию (например позиция 4) то 5 позиция должна остаться неизменной, а 3 -ей станет новость которая была 4, и так далее соответственно

Код

UPDATE table
SET sort = 1+((sort-2) mod @new_pos) 
WHERE sort <= @new_pos

Цитата(jsharp36 @  8.9.2015,  17:16 Найти цитируемый пост)
А второй запрос работает? 

Да, после рихтовки снитаксиса.
Цитата(jsharp36 @  8.9.2015,  17:16 Найти цитируемый пост)
И ваш запрос:
Код

UPDATE `table` t1, `table` t2
SET t1.sort = t2.sort, t2.sort = t1.sort
WHERE t1.id = 5 AND t2.id = 4

так же свалится. В какой-то момент в таблице будет два одинаковых значения.

Нет. Ни в один из моментов дублирования нет - каждая атомарка меняет местами два значения.


--------------------
 О(б)суждение моих действий - в соответствующей теме, пожалуйста. Или в РМ. И высшая инстанция - Администрация форума.

PM MAIL WWW ICQ Jabber   Вверх
Ответ в темуСоздание новой темы Создание опроса
0 Пользователей читают эту тему (0 Гостей и 0 Скрытых Пользователей)
0 Пользователей:
« Предыдущая тема | Составление SQL-запросов | Следующая тема »


 




[ Время генерации скрипта: 0.1196 ]   [ Использовано запросов: 22 ]   [ GZIP включён ]


Реклама на сайте     Информационное спонсорство

 
По вопросам размещения рекламы пишите на vladimir(sobaka)vingrad.ru
Отказ от ответственности     Powered by Invision Power Board(R) 1.3 © 2003  IPS, Inc.