-
Подскажите пожалуйста какой-нибудь удобный способ задания порядка записей. Т.е. на форме лежит TDBGrid, но данные в нём должны отображаться не в порядке ввода, а в том порядке, в каком укажет пользователь (он может перемещать записи вверх/вниз с помощью соответствующих кнопок). Единственное, что я смог придумать, это дополнительное поле в таблице типа INTEGER в котором и будет храниться порядково отображаемый номер и выбирать записи нужно с ORDER BY по этому полю. Но допустим поьзователь добавил 1000 записей и хочет сделать тысячную запись первой - тогда получается нужно обновтить все 1000 записей: в первое поле вместо 1 записать 1000, во второе вместо 2 записать 1, в третье вместо 3 записать 2 и т.д. :( Может есть способ получше?
-
> [0] Валигози2 (31.03.10 15:41) > Может есть способ получше?
Можно сказать пользователю что бы он шел далеко и надолго с такими задачами. 8-) Какой смысл во всем этом? Что за предметная область? Дело в том, что выбрав условно записи из таблицы с 1 по 100 один юзер играется с их порядком. В это время другой пользователь может играться с другой выборкой (записи с 50 по 150). И что будет в итоге? Если же условия выборок не пересекаются гарантировано, то доп поле решит ИМХО проблему. Я так делал - работало.
-
+1 Sergey13 © (31.03.10 16:10) [1]
Валигози2 если ничего не хочется особо делать, то можно записать и 0 допустим поьзователь добавил 1000 записей и хочет сделать тысячную запись первой - тогда получается нужно обновтить все 1000 записей: в первое поле вместо 1 записать 1000, во второе вместо 2 записать 1, в третье вместо 3 записать 2 и т.д.
или -1 или -123
-
> Sergey13 © (31.03.10 16:10) [1] > > [0] Валигози2 (31.03.10 15:41) > > Может есть способ получше? > > Можно сказать пользователю что бы он шел далеко и надолго > с такими задачами. 8-) > Какой смысл во всем этом? Что за предметная область? Дело > в том, что выбрав условно записи из таблицы с 1 по 100 один > юзер играется с их порядком. В это время другой пользователь > может играться с другой выборкой (записи с 50 по 150). И > что будет в итоге? > Если же условия выборок не пересекаются гарантировано, то > доп поле решит ИМХО проблему. Я так делал - работало.
Это таблица производителей продукции и одно из полей типа BLOB содержит картинку бренда производителя. Некоторые производители более "привилегированные" и поэтому их бренды должны отображаться ещё на первой странице. p.s. Забыл уточнить, что база "single user" так что "условия выборок не пересекаются гарантировано".
> 12 © (31.03.10 16:15) [2] > +1 > Sergey13 © (31.03.10 16:10) [1] > > Валигози2 > если ничего не хочется особо делать, то можно записать и > 0 > допустим поьзователь добавил 1000 записей и хочет сделать > тысячную запись первой - тогда получается нужно обновтить > все 1000 записей: в первое поле вместо 1 записать 1000, > во второе вместо 2 записать 1, в третье вместо 3 записать > 2 и т.д. > > или -1 > или -123
В данном примере такая хитрость сработает, но не в случае когда пользователь захочет поставить "тысячную" запись на второе место или третье или вообще в середину... :(
-
> [3] Валигози2 (31.03.10 16:56) > Некоторые производители более "привилегированные" и поэтому > их бренды должны отображаться ещё на первой странице.
Ну так и сделай таблицу рейтингов 1 - Круче некуда 2 - Крутой, но без крыши ... N - фуфло
присвой их "брендам" и сортируй с учетом рейтинга.
-
> В данном примере такая хитрость сработает, но не в случае > когда пользователь захочет поставить "тысячную" запись на > второе место или третье или вообще в середину... :(
а если доп.поле не integer а double?
-
> Sergey13 © (31.03.10 16:59) [4] > > [3] Валигози2 (31.03.10 16:56) > > Некоторые производители более "привилегированные" и поэтому > > > их бренды должны отображаться ещё на первой странице. > > Ну так и сделай таблицу рейтингов > 1 - Круче некуда > 2 - Крутой, но без крыши > ... > N - фуфло > > присвой их "брендам" и сортируй с учетом рейтинга.
Боюсь чтобы заказчик не забраковал такой вариант, хотя попробую предложить... Спасибо :)
> 12 © (31.03.10 17:20) [5] > > > В данном примере такая хитрость сработает, но не в случае > > когда пользователь захочет поставить "тысячную" запись > на > > второе место или третье или вообще в середину... :( > а если доп.поле не integer а double?
Хм. Интересно... Такое мне в голову даже не приходило... Спасибо за идею - поэкспериментирую... :)
-
> а если доп.поле не integer а double?
то ж самое, что номера не по порядку, а через сотню, например а перемена места ведет к появлению номера посередине интервала например 0, 100, 200, 300 -> 0, 50, 100, 200 эта 300 стала 50
-
> Правильный$Вася (31.03.10 20:57) [7] > > а если доп.поле не integer а double?то ж самое, что номера > не по порядку, а через сотню, напримера перемена места ведет > к появлению номера посередине интерваланапример0, 100, 200, > 300 -> 0, 50, 100, 200эта 300 стала 50
Ну это понятно. Помню в старые времена когда писали на бейсике, то нумеровали строки программы через десяток, на случай, чтобы можно было добавить строки внутрь без перенумерации. Правда здесь есть дилема - если сделать слишком маленький шаг, то его может не хватить для вставки внутрь; если сделать слишком большой шаг, то может не хватить размера Int32 для добавления в конец. Впрочем, вместо Int32 можно использовать Int64, тогда можно сделать достаточно большой шаг (например миллион или 10 миллионов) не боясь выйти за рамки, а уж в крайнем случае предусмотреть полную (и долгую, но не частую) перенумерацию всей таблицы. Хотя это можно предусмотреть и в рамках Int32, только насильную перенумерацию прийдётся делать немного чаще (при условии слишком активного перемещения записей)...
-
Из своего скромного опыта единственный случай помню, когда заказчик хотел, чтобы бух.проводки располагались в порядке, который ему удобен, причем он мог этот порядок произвольно менять как ему приятнее (например, по важности операций). Для этого пришлось действительно ввести доп.поле-ключ типа "Номер пп". Во всех остальных случаях универсальный метод-дать возможность юзеру сортировать записи как ему нужно и указанный им порядок просто сохранять в настройках и использовать при следующей загрузке приложения автоматически. Жалоб не бывает.
-
> Во всех остальных случаях универсальный метод-дать возможность > юзеру сортировать записи как ему нужно и указанный им порядок > просто сохранять в настройках и использовать при следующей > загрузке приложения автоматически. Жалоб не бывает.
+1 У меня на выбор 4 варианта. Три стандартных и один пользовательский.
-
> а если доп.поле не integer а double? > > то ж самое, что номера не по порядку
не тоже самое от 0 до 1 бесконечность вещественных чисел машинных double конечно поменьше, но тоже хватит за глаза
-
вообще, AbsoluteDB вроде как файл сервер? во всяком случае может им быть. использует dBase/+ какой то свой расширенный формат. если все так, то какие проблемы? открываем таблицей, и меняем записи физически. у dbf таблиц физический порядок есть.
-
> и меняем записи физически. не сами записи конечно, а значения в них, друг с другом. (и инсерт там команда должно работать именно вставкой, а не добавлением...)
-
> [3] Валигози2 (31.03.10 16:56) > Забыл уточнить, что база "single user"
Т.е. он это чисто для себя делает? Что бы не забыть поздравить с днем рожденья богатого партнера? Тогда я бы перестал оперировать такими масштабами, как "допустим поьзователь добавил 1000". ИМХО он эту тысячу будет несколько лет заводить, если это действительно "таблица производителей продукции".
-
> sniknik (01.04.2010 09:09:12) [12]
Это от незнания, формат dbf не поддерживается. Физический порядок не поддерживается, пишется в любую дырку. Движок относится к классу необслуживаемых, сам обнаруживает проблемы и сам лечит их. Хороший движок. И к тому же embeded как движок, так и БД
-
Делается собственное поле типа sortorder, которое динамически вычисляется...
-
> Sergey13 © (01.04.10 10:16) [14] > > [3] Валигози2 (31.03.10 16:56)> Забыл уточнить, что > база "single user"Т.е. он это чисто для себя делает? Что > бы не забыть поздравить с днем рожденья богатого партнера? > Тогда я бы перестал оперировать такими масштабами, как "допустим > поьзователь добавил 1000". ИМХО он эту тысячу будет несколько > лет заводить, если это действительно "таблица производителей > продукции".
Теоретически он единственный который имеет права добавлять/редактировать данные о производителях (но не обязательно). А информацию о продуктах этих производителей будет набирать множество людей. Причём главное условие, чтобы всё работало без сети. Каждый набивает данные на своей машине, а потом каким либо образом (наверно флэшками) эти данные должны вливаться в основную базу. Так что мне ещё предстоит придумать как это лучшим образом реализовать. В идеальном случае можно будет даже из основной базы удалять (или ещё может чтото делать) все записи определённого оператора (т.е. каждая запись ещё должна "помнить" кто её набрал)... Ну это уже другая история... А по поводу вопроса из этого топика - я сделал так: Дополнительное поле (я его назвал "Slot") типа Int32. Записи в этом поле нумеруются от 1 до N (где N - количество всего записей в таблице). Когда добавляется новая запись - на событии AfterInsert тут же присваивается значение поля "Slot":
procedure TDM.qu_BrandsAfterInsert(DataSet: TDataSet);
begin
qu_BrandsSlot.AsInteger:=qu_Brands.RecordCount+1;
BrandsInput_Form:=TBrandsInput_Form.Create(nil);
try
if BrandsInput_Form.ShowModal=mrOk then DataSet.Post else DataSet.Cancel;
finally
BrandsInput_Form.Free;
end;
end;
Когда пользователь нажимает кнопку вверх (чтобы переместить запись выше) происходит следующее:
procedure TMain3Form.btBrands_upClick(Sender: TObject);
var
CurId, CurSlot: Integer;
begin
if not DM.qu_Brands.Active or DM.qu_Brands.IsEmpty then Exit;
CurId:=DM.qu_Brandsid.AsInteger;
CurSlot:=DM.qu_BrandsSlot.AsInteger;
if CurSlot=1 then Exit;
DM.qu_trans.Close;
DM.qu_trans.SQL.Text:=
'UPDATE tbBrands SET Slot='+IntToStr(CurSlot)+' WHERE Slot='+IntToStr(CurSlot-1)+';'+
'UPDATE tbBrands SET Slot='+IntToStr(CurSlot-1)+' WHERE id='+IntToStr(CurId)+';';
DM.qu_trans.ExecSQL;
DM.qu_Brands.Refresh;
end;
А по нажатию кнопки вниз наоборот:
procedure TMain3Form.btBrands_downClick(Sender: TObject);
var
CurId, CurSlot: Integer;
begin
if not DM.qu_Brands.Active or DM.qu_Brands.IsEmpty then Exit;
CurId:=DM.qu_Brandsid.AsInteger;
CurSlot:=DM.qu_BrandsSlot.AsInteger;
if CurSlot=DM.qu_Brands.RecordCount then Exit;
DM.qu_trans.Close;
DM.qu_trans.SQL.Text:=
'UPDATE tbBrands SET Slot='+IntToStr(CurSlot)+' WHERE Slot='+IntToStr(CurSlot+1)+';'+
'UPDATE tbBrands SET Slot='+IntToStr(CurSlot+1)+' WHERE id='+IntToStr(CurId)+';';
DM.qu_trans.ExecSQL;
DM.qu_Brands.Refresh;
end;
Единственная загвоздка у меня была с удалением записи. Я её решил так:
procedure TDM.qu_BrandsBeforeDelete(DataSet: TDataSet);
begin
FDeleted_BrandsSlot:=qu_BrandsSlot.AsInteger;
end;
procedure TDM.qu_BrandsAfterDelete(DataSet: TDataSet);
begin
qu_trans.SQL.Text:='UPDATE tbBrands SET Slot=(Slot-1) WHERE Slot>'+IntToStr(FDeleted_BrandsSlot);
qu_trans.ExecSQL;
end;
-
> Способ задания порядка записей [D6, AbsoluteDB]
Не использовать DBAware. Отдельные два поля: int в которых хранятся ссылки на левую и правую ближайшие записи. Т.е. организуем линейный связанный список. Построение "ручками", например, в StringGrid.
-
Реализация "перетаскивания" судя по всему по кнопке. Просто супер ! Если я захочу единственную запись с 1000-й позиции перетащить на первую, кликнув 999 раз, то база "содрогнется" 999 раз !!!
Если так уж приспичило все же "перетаскивать", то реализовывать нужно так:
ВСЯ таблица тянется на клиент и запоминается там (например через TClientDataSet или даже обычный стрингрид). Далее пользователь тягает что угодно и куда угодно - перемещение записи вверх или вниз реализуется примитивно посредством обмена данными между записью - источником и записью - приемником. При этом все операции с НД выполняются строго на клиенте. Безо всякой базы !!!
По кнопке "сохранить" таблица БД полностью очищается, НД сканируется и каждая запись добавляется в таблицу с ее новым номером порядковым.
Все будет замечательно работать, НО ! Следует сразу забыть о многопользовательском доступе к БД. Ибо нормального решения для совместного использования таблицы, изменяемой таким трахнутым способом, просто не существует. И еще. Нельзя (по крайней мере потенциально страшно граблиабельно) нигде в БД использовать ссылки на эту таблицу.
-
> Jeer © (01.04.10 21:23) [18] > > > Способ задания порядка записей [D6, AbsoluteDB] > > Не использовать DBAware. > Отдельные два поля: int в которых хранятся ссылки на левую > и правую ближайшие записи. Т.е. организуем линейный связанный > список. > Построение "ручками", например, в StringGrid.
Первоначально я и хотел сделать без использования компонентов DBAware (в таком случае я бы и не написал этот вопрос в форуме) и если эта функция окажется очень важной для заказчика и он будет заострять на ней внимание, то прийдётся таки переделать. Просто хотелось сделать попроще, а насчёт двусвязного списка, то для данных в памяти это хорошее решения, но для баз данных помоему это лишнее усложнение...
> MsGuns © (01.04.10 23:46) [19] > Реализация "перетаскивания" судя по всему по кнопке. Просто > супер ! > Если я захочу единственную запись с 1000-й позиции перетащить > на первую, кликнув 999 раз, то база "содрогнется" 999 раз > !!!
:) Именно так. Пусть заказчик пощёлкает, может откажется от такой идеи... :) А если серьёзно, то это основной способ. Однако если заказчику приспичит, можно и другие способы перемещения добавить. Например, в моём варианте можно добавить способ когда при нажатии одной кнопки текущая запись запоминается, потом перематываешь куда нужно нажимаешь другую кнопку и та запись перемещается на новое место. Наверно можно придумать и если нужно переместить не одну запись а несколько одновремменно, однако как я уже писал, в таком случае лучше уже делать не с помоью DBAware компонентов..
> Если так уж приспичило все же "перетаскивать", то реализовывать > нужно так: > > ВСЯ таблица тянется на клиент и запоминается там (например > через TClientDataSet или даже обычный стрингрид). > Далее пользователь тягает что угодно и куда угодно - перемещение > записи вверх или вниз реализуется примитивно посредством > обмена данными между записью - источником и записью - приемником. > При этом все операции с НД выполняются строго на клиенте. > Безо всякой базы !!!
В моём случае нет смысла гонять таблицу туда-сюда по TClientDataSet, так как программа работает без сети (и сеть не предполагается), программа открывает базу в эксклюзивном режиме, все накопленные данные с разных машин собираются на основной флешками или RW-дисками (какому оператору что удобнее)
> По кнопке "сохранить" таблица БД полностью очищается, НД > сканируется и каждая запись добавляется в таблицу с ее > новым номером порядковым. > > Все будет замечательно работать, НО ! > Следует сразу забыть о многопользовательском доступе к БД. > Ибо нормального решения для совместного использования таблицы, > изменяемой таким трахнутым способом, просто не существует. > > И еще. Нельзя (по крайней мере потенциально страшно граблиабельно) > нигде в БД использовать ссылки на эту таблицу.
В таком случае никакой пользы от этой таблицы нет, так как это таблица производителей, и на неё по-любому будет ссылаться продукция (информацио о которой набирают операторы вообще отрезанные от сети). А в варианте, когда не перезаписыватся таблица полностью - такой проблемы нет.
-
> [17] Валигози © (01.04.10 20:29) > а потом каким либо образом (наверно флэшками) эти данные > должны вливаться в основную базу.
И есди записи от разных набивателей совпадают, то.....?
> Так что мне ещё предстоит придумать как это лучшим образом реализовать. Я бы на твоем месте занялся С САМОГО НАЧАЛА этим вопросом. Навешивание рюшечек это крайний с конца этап проектирования приложения.
> Теоретически он единственный ИМХО тебе в постановке задачи не хвататет практичности. Все теоретические изыски заказчика ты все равно не удовлетворишь. Что это должно быть в оригинале то? Про что программа.
> [19] MsGuns © (01.04.10 23:46) > По кнопке "сохранить" таблица БД полностью очищается
А так же все завязаные на нее дочки во всех коленах? Забавно.
-
> Sergey13 © (02.04.10 09:48) [21] > > [17] Валигози © (01.04.10 20:29) > > а потом каким либо образом (наверно флэшками) эти данные > > > должны вливаться в основную базу. > > И есди записи от разных набивателей совпадают, то.....?
Они не могут совпасть, так как каждая запись снабжается кроме порядкового id, также и уникальным кодом оператора. А вот с тем, что оператор мог в своей базе добавить инфу производителя, который уже прописан в базе пусть разгребается заказчик (что заказывал, то и получил :)). Заказчику же предоставляется возможность деактивировать любую запись и даже одним нажатием деактивировать все записи определённого оператора. Впрочем, заказчик попросил, чтобы инфу о производителях мог добавлять только строго один он (хотя я и добавил в администраторском управлении возможность администратору разрешать/запрещать эту возможность любому оператору)
> > Так что мне ещё предстоит придумать как это лучшим образом > реализовать. > Я бы на твоем месте занялся С САМОГО НАЧАЛА этим вопросом. > Навешивание рюшечек это крайний с конца этап проектирования > приложения.
Во-первых заказчик хочет видеть всё и сразу :) Во-вторых я ещё сам не представляю как будет выгледеть окончательный вариант, поэтому я в проге набросал множество бутафории, чтобы заказчик ткнул в чтото что нужно переделать, прежде чем я к этой бутафории напишу рабочий код...
> > Теоретически он единственный > ИМХО тебе в постановке задачи не хвататет практичности. > Все теоретические изыски заказчика ты все равно не удовлетворишь.
Все - конечно нет, об этом даже не может быть и речи :) Но хотелось бы по-максимуму...
> Что это должно быть в оригинале то? Про что программа.
Обещал заказчику "неразглашение" :) И так уже много чего выболтал... :)))
> > [19] MsGuns © (01.04.10 23:46) > > По кнопке "сохранить" таблица БД полностью очищается > > А так же все завязаные на нее дочки во всех коленах? Забавно.
То-то и оно...
-
> [22] Валигози2 (02.04.10 10:31)
> Во-первых заказчик хочет видеть всё и сразу :) Он может хотеть увидеть даже прекрасных гурий в райских кущщах, но это никак не связано с проектированием приложения. Это как в строительстве - есть отделка фасада и есть фундамент.
> Обещал заказчику "неразглашение" :) И так уже много чего выболтал... :))) Детский садик "Ромашка", старшая группа. Там тоже после просмотра Смешариков в секретики играют. Впрочем мне пофиг - это ты пишешь эту прогу.
-
> Валигози2 (02.04.2010 10:31:22) [22]
> Обещал заказчику "неразглашение" :) И так уже много чего выболтал... :)))
Теперь тебя посадят и расстреляют.
-
> Sergey13 © (02.04.10 10:45) [23] > > [22] Валигози2 (02.04.10 10:31) > > > Во-первых заказчик хочет видеть всё и сразу :) > Он может хотеть увидеть даже прекрасных гурий в райских > кущщах, но это никак не связано с проектированием приложения. > > Это как в строительстве - есть отделка фасада и есть фундамент.
В идеале, сначала лучше построить макет, а то после фундамента может не подойти тот фасад как его видит заказчик...
> > Обещал заказчику "неразглашение" :) И так уже много чего > выболтал... :))) > Детский садик "Ромашка", старшая группа. Там тоже после > просмотра Смешариков в секретики играют. > Впрочем мне пофиг - это ты пишешь эту прогу.
Я знаю ;)
> Anatoly Podgoretsky © (02.04.10 11:15) [24] > > Валигози2 (02.04.2010 10:31:22) [22] > > > Обещал заказчику "неразглашение" :) И так уже много чего > выболтал... :))) > > Теперь тебя посадят и расстреляют.
Надеюсь, что заказчик не читает форумы по программировнию :))) Кстати, заметил, что AbsoluteDB в режиме MultiUser иногда при закритии приложения выдаёт какую-то ошибку о том, что типа чтото не все транзакции подтверждены и если после этого заглянуть в базу, то не всё изменения применяются... Впрочем, для моей задачи MultiUser не требуется, а в режиме SingleUser AbsoluteDB пока работает без замечаний...
-
> [25] Валигози2 (02.04.10 13:15) > что типа чтото не все транзакции подтверждены
Что ж ты их не подтвердил?
-
> Sergey13 © (02.04.10 14:24) [26] > > [25] Валигози2 (02.04.10 13:15) > > что типа чтото не все транзакции подтверждены > > Что ж ты их не подтвердил?
Дело в том, что я их вообще не использую. В тех двух местах, где использовал - переделал без транзакций сразу как заметил этот глюк, но дело оказалось не в этом...
-
> [27] Валигози2 (02.04.10 14:52) > Дело в том, что я их вообще не использую.
Дело в том, что ты их видимо используешь, хотя может и не догадываешься об этом. Но незнание закона, как известно, не освобождает от ответственности.
-
> Валигози2 (02.04.2010 14:52:27) [27]
Так, теперь переделывай обратно и больше так не делай
-
> Валигози2 (31.03.10 15:41)
Можно использовать такой вариант: добавить ещё одну таблицу с двумя полями - Id,SortOrder, по Id связанную с основной и обновлять её для сортировки. В-принципе, алгоритм достаточно простой при перемещении записей.
-
> Sergey13 (31.03.2010 16:10:01) [1]
Он и так пойдет после первого использования.
-
> Демо (02.04.2010 15:44:30) [30]
Гениально
-
> Anatoly Podgoretsky © (02.04.10 18:01) [32] > > Демо (02.04.2010 15:44:30) [30]Гениально
Ну какой-никай - выход. Таблицу с одним неключевым полем проще обновить и быстрее.
-
> Anatoly Podgoretsky © (02.04.10 18:01) [32] > > > Демо (02.04.2010 15:44:30) [30] > > Гениально
Это частное решение более общего, потому гениальность не замечена. С учетом [33] - все зависит от техники, СУБД, конкретного вида первичной таблицы ( стоит ли выносить sortorder в отдельную )
-
По поводу секретности - это, как я понял, апрельский прикол ? Не то чтобы смешно, но это такое.. Даю 90% что вы вообще это (в смысле перетаскивание с перенумерацией как вы их тут описали) не реализуете, и 100% что если все ж таки реализуете, никто больше месяца с этой прогой работать не будет ибо поумирают от инфарктов
|