Главная страница
Top.Mail.Ru    Яндекс.Метрика
Текущий архив: 2008.07.06;
Скачать: CL | DM;

Вниз

Странное поведение выборки в Access   Найти похожие ветки 

 
DimonS   (2008-06-06 07:43) [0]

Добрый день (ну или у кого что) всем.

Столкнулся с таким траблом, в первый раз, так что не пинайте если уже объясняли.
Есть две абсолютно одинаковых по структуре базы 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-06 10:53) [1]

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. выяви самый медренный участок в коде...


 
sniknik ©   (2008-06-06 11:02) [2]

> из dBase в Access кидается запросто, а вот в таком случае незнаю
в хелпе примеры есть и для "таких случаев".


 
Anatoly Podgoretsky ©   (2008-06-06 11:18) [3]

Надо поизучать SQL и заменить на один запрос, без цикла


 
Slym ©   (2008-06-06 12:19) [4]

насколько быстрее такой код? (Расставь конекшены)

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;


 
DimonS   (2008-06-07 02:16) [5]


> 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]

Это я и сам знаю, учу по мере возможностей :).

А вообще, основной вопрос так и остался - почему выбираются записи по времени меньшие, чем назначено в выборке?


 
DimonS   (2008-06-07 04:08) [6]

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

> 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; в режиме отладки показывает значение этого поля. Буду разбираться дальше.
А вообще, код интересный, спасибо за него, разобрался что к чему :)


 
ASoft   (2008-06-07 04:39) [7]


> ...как из одной базы Access запросом перебросить данные в другую...

TADOCommand:
INSERT INTO таблица  [ ( поле [,...] ) ]
{ VALUES ( Wertliste [,...] ) } | SELECT-команда ;


 
DimonS   (2008-06-07 04:47) [8]


> ASoft   (07.06.08 04:39) [7]

Ну да. Базы на разных сетевых адресах, как в запросе указать к ним путь? Нужно ведь указать путь, название базы и еще таблицу в базе. На этом то я и споткнулся.


 
Slym ©   (2008-06-07 06:43) [9]

DimonS   (07.06.08 4:08) [6]
Ошибка "List index out not found(47)".

мой косяк :)
InsCmd.Parameters[i-1].Value:=Source.Fields[i].Value;


 
Slym ©   (2008-06-07 06:45) [10]

ты даже не представляешь во сколько раз будет быстрее если базу еще и монопольно открыть...


 
DimonS   (2008-06-07 07:21) [11]


> Slym ©   (07.06.08 06:45) [10]
> ты даже не представляешь во сколько раз будет быстрее если
> базу еще и монопольно открыть...


Вот этого и нельзя сделать. К сожалению. Про увеличение скорости в монопольном режиме я вкурсе. База постоянно пополняется/изменяется.


 
DimonS   (2008-06-07 07:50) [12]

To Slym
Щас достану наверное :)


> InsCmd.Parameters[i-1].Value

Да, действительно, так работает. Сразу не дошло :)

Но вот в чем прикол оказался - при вставке записей в поля формата Дата/время вставляется только дата, времени нет.
Вроде в строке

InsCmd.Parameters[i].Value:=Source.Fields[i].Value;
нет никаких ограничений. Что может быть? Остальные поля вставляются нормально.


 
sniknik ©   (2008-06-07 08:26) [13]

> Если про стандартный хелп MS Access,
именно, хотя я чтобы не запускать access(может вообще не установлен) просто открываю его файл справки - JETSQL40.CHM.
> то не нашел ничего,
раздел "Предложение IN"
> да там вообще толком-то ничего нет.
???? там есть все. все что вообще есть книги/описания/статьи в инете, все оттуда взято...

> нет никаких ограничений. Что может быть?
параметр/значение может быть целочисленного типа, тогда сработает авто приведение типа.
проверь их типы.


 
Slym ©   (2008-06-09 08:14) [14]

DimonS   (07.06.08 7:50) [12]
нет никаких ограничений. Что может быть? Остальные поля вставляются нормально

если Source создается динамически (как я привел выше), то искать проблему нужно в ДБ и форматах полей/отображения



Страницы: 1 вся ветка

Текущий архив: 2008.07.06;
Скачать: CL | DM;

Наверх




Память: 0.51 MB
Время: 0.02 c
2-1212728038
Julia
2008-06-06 08:53
2008.07.06
пароль на .MDB


2-1212825750
TUserClass
2008-06-07 12:02
2008.07.06
OnMouseEnter и OnMouseLeave для всего ...


2-1212984332
Димон
2008-06-09 08:05
2008.07.06
Вопрос


2-1212579950
Гость
2008-06-04 15:45
2008.07.06
Как ограничить кол-во символов в Label


6-1186510169
Балбес
2007-08-07 22:09
2008.07.06
TServerSocket и несколько подключений