Форум: "Базы";
Текущий архив: 2004.06.20;
Скачать: [xml.tar.bz2];
ВнизИсключение записи из выборки Найти похожие ветки
← →
Rouse_ © (2004-05-25 14:03) [0]Ситуация:
при помощи ADOQuery делаю выборку записей и модифицирую их по определенному алгоритму...
Но иногда бывает что в выборку попадают записи которые в данный момент мне не нужны.
В качестве примера:
производим поиск всех записей начинающихся с букв "ул"
в результате имеем кучу записей выглядящих как:
"улица Каширская"
"ул. Пролетарская"
но среди них затесывается иногда и такое:
"Ульяновск"
"Улан-Удэ"
(данные привел просто как пример)
Теперь вопрос:
Можно ли как нибудь исключить записи мне не подходящие в данный момент из общей выборки?
Свойства Remove я к сожалению не нашел...
Почему не подходит модификация запроса в виде WHERE?
Потому что сам запрос выполняется в течении нескольких секунд и с каждой удаленной таким макаром записью ждать заново еще несколько секунд некрасиво...
Почему не подходит фильтр?
Фильтр может быть и подходит, но в дальнейшем я передаю всю выборку в таблицу таким способом:
ADOTable.RecordSet := ADOQuery.RecordSet;
и продолжаю работать уже через таблицу...
По всей видимости придется плодить строку фильтра с каждым удалением.
А есть ли более элегантный способ исклюдения записи из выборки (не удаления ее из физической таблицы)
← →
Sandman25+1 (2004-05-25 14:08) [1]Не уверен, что правильно понял, но все же попробую.
Если нельзя написать update и очень хочется работать именно с While not Eof do ... Next, то я бы в этот цикл добавил вызов функции, возвращающей значение True только для тех записей, которые нужно изменять.
← →
Vlad © (2004-05-25 14:11) [2]
> Sandman25+1 (25.05.04 14:08) [1]
> то я бы в этот цикл добавил вызов функции, возвращающей
> значение True только для тех записей, которые нужно изменять
Ну это фактически тоже что и DataSet.OnFilterRecord
← →
Sandman25+1 (2004-05-25 14:16) [3][2] Vlad © (25.05.04 14:11)
OnFilterRecord может использоваться другими свойствами/методами TDataSet, в том числе и RecordSet, а пользовательская функция заведомо никем не используется. Хотя, возможно, действительно нет никакой разницы.
← →
Rouse_ © (2004-05-25 14:19) [4]Нет, понял ты конечно правильно но немного не так :)
см > [2] Vlad © (25.05.04 14:11) :)
А нужно именно исключение вручную из уже сделанной выборки определенных записей...
т.е. я их пробежал, щелкнул на одной, нажал кнопку исключить и она уже не в текущей выборке (но осталась в основной базе)
нашел следущую, также руками выделяем, жмем "исключить" и так пока не просмотрим всю выборку и убедимся что она подходит нам для того чтобы передать ее некой процедуре для дальнейшей работы уже с получившейся выборкой записей...
← →
Sandman25+1 (2004-05-25 14:25) [5][4] Rouse_ © (25.05.04 14:19)
Так это пользовательский выбор? Можно сделать новый TClientDataSet, перекачать в него данные, а потом пользователь бы удалял все, что он хочет.
Либо как альтернатива, использовать CashedUpdates=true. Только не уверен, что это подойдет для AdoQuery.
← →
Vlad © (2004-05-25 14:26) [6]
> Rouse_ © (25.05.04 14:19) [4]
Используй TClientDataSet или TADODataSet (по-моему там тоже можно отвязать данные от базы), и удаляй из клиентского набора данных, но при этом не отражай в базе.
← →
DenK_vrtz © (2004-05-25 14:28) [7]как вариант
DBGrid1 c включенной dgMultiSelect
А потом цикл по DataSet c проверкой выделения строки и update
← →
Vlad © (2004-05-25 14:40) [8]Впринципе вопрос, как я понял сводится к следующему:
нужно удалить данные из DataSet, но не удалять физически из таблицы. Так ?
Тут еще как вариант, можно было бы использовать транзакции. То есть открываешь транзакцию, удаляешь записи из ADOQuery, затем делаешь с Recordset все необходимые действия, и в конце - откат транзакции.
Но если речь идет о Access, например, то не уверен что там вобще существует понятие транзакций. В этом случае попробуй вариант с клиентским набором данных ([6])
← →
Rouse_ © (2004-05-25 15:19) [9]Да, сейчас попробую через ClientDataSet
Фильтр по некоторой причине не подошел...
← →
Rouse_ © (2004-05-25 23:12) [10]Все же сделал на фильтрах - при более глубоком разборе они оказались самым оптимальным вариантом...
Жаль конечно, я думал что sniknik&Polevi - подскажут вариант решения проблемы, но после разбора кода самих компонентов оказалось что решения именно так, как я себе представлял (Remove определенной записи в наборе) не существует... Хотя я просто мог его не найти или не обратитть на него внимания... (что маловероятно)
Мне думается если мои доводы верны - то это большое упущение со стороны Борланда (а именно модификация уже полученной выборки без дополнительных ухищрений)
Но это так... мое ИМХО.
Всем спасибо.
← →
sniknik © (2004-05-25 23:59) [11]> модификация уже полученной выборки без дополнительных ухищрений
на клиенте легко.
...
ADODataSet.Open;
ADODataSet.Connection:= nil;
ADODataSet.Delete; <- базу не затронет
либо ставиш ltBatchOptimistic и тоже удаляй как хочеш только UpdateBatch не делай, тогда тоже ничего в базе не изменится.
но ты вроде в запросе хотел, там только один способ модифицировать выборку после командой SQL, HAVING но тебе не подойдет, хотя запрос и не показан но думаю групировки у тебя нет.
можно еще запрос из подзапроса сделать (неуказана база, может не поддерживает) и там уже добавить ограничений, но только зря это (имхо) проще условие в основном сделать точнее.
← →
Sandman25+1 (2004-05-26 09:03) [12][11] sniknik © (25.05.04 23:59)
>но ты вроде в запросе хотел, там только один способ модифицировать выборку после командой SQL, HAVING но тебе не подойдет
Что Вы имеете в виду? Having - точно такая же часть select, как и where или from.
← →
sniknik © (2004-05-26 10:28) [13]> Что Вы имеете в виду?
SELECT * FROM Table1 HAVING ID = 0
-> EOleException : Предложение HAVING (ID=0) без группировки
SELECT ID, First(Name) FROM Table1 GROUP BY ID HAVING ID = 0
-> ok
какой запрос в вопросе? я лично его вообще не вижу.
← →
Polevi © (2004-05-26 10:32) [14]>Rouse_ © (25.05.04 23:12) [10]
тебе нужен отсоединенный датасет
tempDataset:=TADODataset.Create(nil);
try
tempDataset.RecordSet=ADOQuery1.Recordset;
while not tempDataset.Eof do
begin
if condition then
tempDataset.Delete;
tempDataset.Next;
end;
finally
tempDataset.Free;
end;
ADOTable1.RecordSet=tempDataset.Recordset;
← →
Polevi © (2004-05-26 10:33) [15]PS
сорри, tempDataset.Free в конце еснно :)
← →
Rouse_ © (2004-05-26 10:37) [16]Во, спасибо - сделаю при помощи отсоединенного, что-то с ним не догадался поэксперементировать...
А запрос у меня простой
SELECT * FROM MainTable WHERE StreetName LIKE "ул%"
где
MainTable - имя таблицы
StreetName - имя колонки
← →
Sandman25+1 (2004-05-26 10:50) [17][13] sniknik © (26.05.04 10:28)
Все равно select остается select"ом, с having он или без.
← →
sniknik © (2004-05-26 10:54) [18]> Потому что сам запрос выполняется в течении нескольких секунд и с каждой удаленной таким макаром записью ждать заново еще несколько секунд некрасиво...
> SELECT * FROM MainTable WHERE StreetName LIKE "ул%"
запрос в таком виде использует индекс (если он есть), и не будет менее "напряжным" чем такой например
SELECT * FROM MainTable WHERE StreetName LIKE "улица%" or StreetName LIKE "ул.%"
ждать больше не придется.
или
SELECT * FROM MainTable WHERE StreetName LIKE "ул[и.]%"
(хотя в этом случае в использовании тндекса не уверен, по идее должен использоватся)
← →
sniknik © (2004-05-26 10:58) [19]Sandman25+1 (26.05.04 10:50) [17]
а где я чтонибудь против говорил? > [11]? попытайся не только прочитать но и понять (возможно не совсем верно расставлены запятые, но смысл фразы по моему понятен)
← →
Sandman25+1 (2004-05-26 11:05) [20][19] sniknik © (26.05.04 10:58)
Видимо, я уже не пойму. Извините, если что.
← →
Rouse_ © (2004-05-26 11:48) [21]> [14] Polevi © (26.05.04 10:32)
В таком варианте происходит удаление записи из физической таблицы...
вот как я решил данную проблему:procedure TfrmRestructuringTable.mnuRemoveRecClick(Sender: TObject);
function CopyRecordSet(RecordSet: _RecordSet): _RecordSet;
var
adoStream: OleVariant;
begin
adoStream := CreateOLEObject("ADODB.Stream");
try
Variant(RecordSet).Save(adoStream, adPersistADTG);
Result := CreateOLEObject("ADODB.RecordSet") as _RecordSet;
Result.CursorLocation := adUseClient;
Result.Open(adoStream, EmptyParam, adOpenStatic, adLockOptimistic,
adOptionUnspecified);
finally
adoStream := UnAssigned;
end;
end;
var
TempDataset: TADODataSet;
begin
TempDataset := TADODataSet.Create(nil);
try
TempDataset.Recordset := CopyRecordSet(SourceQuery.Recordset);
TempDataset.Delete;
SourceQuery.Recordset := TempDataset.Recordset;
finally
TempDataset.Free;
end;
end;
Всем спасибо за помощь...
← →
Rouse_ © (2004-05-26 12:15) [22]точнее даже вот так лучше переписать:
var
TempDataset: TADODataSet;
Mark: TBookmark;
begin
TempDataset := TADODataSet.Create(nil);
try
TempDataset.Recordset := CopyRecordSet(SourceQuery.Recordset);
TempDataset.MoveBy(SourceQuery.RecNo - 1);
TempDataset.Delete;
Mark := TempDataset.GetBookmark;
try
SourceQuery.Recordset := TempDataset.Recordset;
finally
SourceQuery.GotoBookmark(Mark);
TempDataset.FreeBookmark(Mark);
end;
finally
TempDataset.Free;
end;
end;
← →
sniknik © (2004-05-26 12:16) [23]> Rouse_ © (26.05.04 11:48) [21]
сложно...
гораздо сложнее чем предлагал > ADODataSet.Connection:= nil;
и уж явно копирование всей выборки идет дольше чем простое уточнение условия в WHERE (если считать разницу времени от неточного к точному, именно ее ты добавляеш).
← →
Rouse_ © (2004-05-26 14:13) [24]> [23] sniknik © (26.05.04 12:16)
Дело в том что после удаления ненужных записей у меня останется набор записей важными из которых являются два поля
первое поле ID второе строка типа Улица, дом, корпус, квартира
и мне эти строки необходимо разбить и перетащить каждое значение в другие поля в этой же таблице, а если я удалю запись при отключенной таблице и потом подключусь - то запись то там исчезнет (я так думаю)
короче на данный момент этот вариант полностью устраивает... :)
Страницы: 1 вся ветка
Форум: "Базы";
Текущий архив: 2004.06.20;
Скачать: [xml.tar.bz2];
Память: 0.52 MB
Время: 0.032 c