![]() |
| ||
|
|
Новости |
Поиск |
FAQ |
Статьи |
Книги |
Новости VCL
| | Форумы ЧАТ |
Орешник |
|
| |||
| |||
« предыдущая ветвь | форум | следующая ветвь »
Странное поведение выборки в Access [D7, XP]
DimonS © (2008-06-06 07:43:00)Добрый день (ну или у кого что) всем.
Столкнулся с таким траблом, в первый раз, так что не пинайте если уже объясняли.
Есть две абсолютно одинаковых по структуре базы Access (таблицы и их структура так же одинаковы). Нужно было сделать копирование новых записей из одной в другую - типа репликации, с удалением в основной базе старых записей и сохранением их в другой базе. Код такой:
procedure TForm1.Button1Click(Sender: TObject);
var
i:Integer;
Dat:TDateTime;
begin
ADORep.Close;
ADORep.SQL.Clear;
ADORep.SQL.Add('select Max(Time5) as Dat from PathForms');
ADORep.Open;
Dat:=ADORep.fieldByName('Dat').AsDateTime;
Edit3.Text:=DateTimeToStr(Dat);
ADOData.Close;
ADOData.SQL.Clear;
ADOData.SQL.Add('select * from PathForms where Time5>:Dat');
ADOData.Parameters.ParamValues['Dat']:=Dat;
ADOData.Open;
while not ADOData.Eof do
begin
ADORep.Close;
ADORep.SQL.Clear;
ADORep.SQL.Add('delete from PathForms where Code1=:C1 and Code2=:C2');
ADORep.Parameters.ParamValues['C1']:=ADOData.fieldByName('Code1').AsInteger;
ADORep.Parameters.ParamValues['C2']:=ADOData.fieldByName('Code2').AsInteger;
ADORep.ExecSQL;
ADOData.Next;
end;
ADORep.Close;
ADORep.SQL.Clear;
ADORep.SQL.Add('select Top 1 * from PathForms');
ADORep.Open;
ADOData.First;
while not ADOData.Eof do
begin
ADORep.Insert;
for i:=1 to ADOData.FieldCount-1 do
ADORep.Fields[i].Value:=ADOData.Fields[i].Value;
Dat:=ADOData.Fields[8].Value;
ADORep.Post;
ADOData.Next;
end;
end;
Можете не пинать, сам знаю, что перебор вместо запросов это отстой, но пока не нашел, как из одной базы Access запросом перебросить данные в другую (из dBase в Access кидается запросто, а вот в таком случае незнаю), так что если кто подскажет, то приму к сведению и переработаю код.
Code1, Code2 - ключевые поля.
Time5 - дата/время последнего изменения записи, формат Дата/Время.
А проблема (хотя и не особо проблема) такая. Смотрим на максимальное время в обновляемой таблице:
http://i014.radikal.ru/0806/69/e909c6671dc8.jpg
А теперь время отобранных выборкой записей:
http://i042.radikal.ru/0806/bb/bcc7fa21955e.jpg
ADOData.Fields[8].Value; - это значение поля Time5.
Вопрос: почему выбираются записи с меньшим значением даты/времени?
ЗЫ. Впринципе, это не особо мешает, 2-3 сотни записей обрабатываются в течение нескольких секунд, но все же интересно узнать, что за баг.
ЗЫЗЫ. простой репликой базы нельзя обновить по нескольким причинам, одна из них - базы под паролем.
Slym (2008-06-09 08:14:00) [1]DimonS (07.06.08 7:50) [12]
нет никаких ограничений. Что может быть? Остальные поля вставляются нормально
если Source создается динамически (как я привел выше), то искать проблему нужно в ДБ и форматах полей/отображения
sniknik (2008-06-07 08:26:00) [2]> Если про стандартный хелп MS Access,
именно, хотя я чтобы не запускать access(может вообще не установлен) просто открываю его файл справки - JETSQL40.CHM.
> то не нашел ничего,
раздел "Предложение IN"
> да там вообще толком-то ничего нет.
???? там есть все. все что вообще есть книги/описания/статьи в инете, все оттуда взято...
> нет никаких ограничений. Что может быть?
параметр/значение может быть целочисленного типа, тогда сработает авто приведение типа.
проверь их типы.
DimonS (2008-06-07 07:50:00) [3]To Slym
Щас достану наверное :)
> InsCmd.Parameters[i-1].Value
Да, действительно, так работает. Сразу не дошло :)
Но вот в чем прикол оказался - при вставке записей в поля формата Дата/время вставляется только дата, времени нет.
Вроде в строке
InsCmd.Parameters[i].Value:=Source.Fields[i].Value;
нет никаких ограничений. Что может быть? Остальные поля вставляются нормально.
DimonS (2008-06-07 07:21:00) [4]
> Slym © (07.06.08 06:45) [10]
> ты даже не представляешь во сколько раз будет быстрее если
> базу еще и монопольно открыть...
Вот этого и нельзя сделать. К сожалению. Про увеличение скорости в монопольном режиме я вкурсе. База постоянно пополняется/изменяется.
Slym (2008-06-07 06:45:00) [5]ты даже не представляешь во сколько раз будет быстрее если базу еще и монопольно открыть...
Slym (2008-06-07 06:43:00) [6]DimonS (07.06.08 4:08) [6]
Ошибка "List index out not found(47)".
мой косяк :)
InsCmd.Parameters[ i-1].Value:=Source.Fields[i].Value;
DimonS (2008-06-07 04:47:00) [7]
> ASoft (07.06.08 04:39) [7]
Ну да. Базы на разных сетевых адресах, как в запросе указать к ним путь? Нужно ведь указать путь, название базы и еще таблицу в базе. На этом то я и споткнулся.
ASoft (2008-06-07 04:39:00) [8]
> ...как из одной базы Access запросом перебросить данные в другую...
TADOCommand:
INSERT INTO таблица [ ( поле [,...] ) ]
{ VALUES ( Wertliste [,...] ) } | SELECT-команда ;
DimonS (2008-06-07 04:08:00) [9]Вот сижу, разбираюсь с ышеуказанными исправлениями.
> Slym © (06.06.08 10:53) [1]
Да, такой код работает нормально, спасибо, не знал что так можно. Хотя прибавки в скорости практически не видно.
И про выборку такого вида не встречал пока нигде, но работает нормально.
> Slym © (06.06.08 12:19) [4]
> насколько быстрее такой код? (Расставь конекшены)
Да, работает быстрее раза в три-четыре, но только начало. Спотыкается на этом куске:
for i:=1 to Source.FieldCount-1 do
InsCmd.Parameters[i].Value:=Source.Fields[i].Value;
Ошибка "List index out not found(47)". Понимаю, что типа нет такого поля, но в таблицах 48 полей, таблицы одинаковы по структуре (вторая просто копия первой). Причем при наведении курсора на Source.Fields[i].Value; в режиме отладки показывает значение этого поля. Буду разбираться дальше.
А вообще, код интересный, спасибо за него, разобрался что к чему :)
DimonS (2008-06-07 02:16:00) [10]
> Slym © (06.06.08 10:53) [1]
> Slym © (06.06.08 12:19) [4]
Спасибо за советы, принял к сведению :)
> sniknik © (06.06.08 11:02) [2]
Если про стандартный хелп MS Access, то не нашел ничего, да там вообще толком-то ничего нет.
> Anatoly Podgoretsky © (06.06.08 11:18) [3]
Это я и сам знаю, учу по мере возможностей :).
А вообще, основной вопрос так и остался - почему выбираются записи по времени меньшие, чем назначено в выборке?
Slym (2008-06-06 12:19:00) [11]насколько быстрее такой код? (Расставь конекшены)
procedure Button1Click();
var
Date:TDateTime;
Source:TAdoQuery;
DelCmd,InsCmd:TAdoCommand;
i:integer;
KeyField0,KeyField1:TField;
Fields1,Fields2:string;
begin
Source:=TAdoQuery.Create(nil);
try
//Dest.Connection:=Connection;
Source.CursorType:=ctOpenForwardOnly;
Source.LockType:=ltReadOnly;
Source.SQL.Text:='select Max(Time5) as Dat from PathForms';
Source.Open;
if Source.IsEmpty then raise Exception.Create('IsEmpty');
Date:=Source.Fields[0].AsDateTime;
Source.Close;
//Source.Connection:=Connection;
Source.CursorType:=ctOpenForwardOnly;
Source.LockType:=ltReadOnly;
Source.SQL.Text:='select * from PathForms where Time5>:Dat';
Source.Parameters[0].Value:=Date;
Source.Open;
DelCmd:=TAdoCommand.Create(nil);
try
//DelCmd.Connection:=Connection;
DelCmd.CommandText:='delete from PathForms where Code1=:C1 and Code2=:C2';
DelCmd.Prepared:=true;
Fields1:='';Fields2:='';
for i:=1 to Source.FieldCount-1 do
with Source.Fields[i] do
begin
Fields1:=Fields1+'['+FieldName+'],';
Fields2:=Fields2+':'+FieldName+',';
end;
Delete(Fields1,Length(Fields1),1);
Delete(Fields2,Length(Fields2),1);
InsCmd:=TAdoCommand.Create(nil);
try
//InsCmd.Connection:=Connection;
InsCmd.CommandText:='INSERT INTO PathForms ('+Fields1+') VALUES ('+Fields2+');';
InsCmd.Prepared:=true;
KeyField0:=Source.fieldByName('Code1');
KeyField1:=Source.fieldByName('Code2');
while not Source.Eof do
begin
DelCmd.Parameters[0].Value:=KeyField0.AsInteger;
DelCmd.Parameters[1].Value:=KeyField1.AsInteger;
DelCmd.Execute;
for i:=1 to Source.FieldCount-1 do
InsCmd.Parameters[i].Value:=Source.Fields[i].Value;
InsCmd.Execute;
Source.Next;
end;
finally
InsCmd.Free;
end;
finally
DelCmd.Free;
end;
finally
Source.Free;
end;
end;
Anatoly Podgoretsky (2008-06-06 11:18:00) [12]Надо поизучать SQL и заменить на один запрос, без цикла
sniknik (2008-06-06 11:02:00) [13]> из dBase в Access кидается запросто, а вот в таком случае незнаю
в хелпе примеры есть и для "таких случаев".
Slym (2008-06-06 10:53:00) [14]DimonS (06.06.08 7:43)
замечания по коду:
1. незачем в цикле каждый каз SQL править, можно 1 раз:
ADORep.Close;
ADORep.SQL.Text:='delete from PathForms where Code1=:C1 and Code2=:C2';
while not ADOData.Eof do
begin
ADORep.Parameters.ParamValues['C1']:=ADOData.fieldByName('Code1').AsInteger;
ADORep.Parameters.ParamValues['C2']:=ADOData.fieldByName('Code2').AsInteger;
ADORep.ExecSQL;
ADOData.Next;
end;
2. в п1 можно заранее расчитать индексы полей и параметров, а не дергать fieldByName и ParamValues
3. 'select Top 1 * from PathForms' можно заменить на 'select * from PathForms where false' но лучше состряпать INSERT запрос
4. если к запросам зацеплены Гриды то делать DisableControls
5. выяви самый медренный участок в коде...