Topic: Есть реальная проблема со скриптом

procedure vhod_button8_OnClick (Sender: string; ACol, ARow: Integer; Action: string);
var
   t, mx, m: integer;
   mxtext,sDate: string;
begin
sDate := '"'+ FormatDateTime('yyyy-MM-DD 00:00:00.000',  (vhod.DateTimePicker1.DateTime)) + '"';
t:=SQLExecute('SELECT count(id) FROM kash WHERE date ='+sDate+'');
if t<  SQLExecute('SELECT count(id) FROM azs ;') then
   begin
   m:= SQLExecute('SELECT max(id) FROM azs ;') ;
   end;
   for mx:=1 to m do
   begin
   mxtext:=VarToStr (mx);
  if SQLExecute('SELECT count(id) FROM kash WHERE date ='+sDate+' and id='+mxtext+'') = 0 then
      begin
      SQLExecute('INSERT INTO kash (id_azs, date,gotov) VALUES ('+mxtext+','+sDate+',0);');
      vhod.TableGrid2.dbUpdate;
      UpdateDatabase('kash');
      end;
   end;
end;

суть такая.
1. есть справочник (azs)
2. на форме есть компонент дата (vhod.DateTimePicker1.DateTime)
3. запуская процедуру мы проверяем наличие записей в таблице (kash) на соответствие то чтобы кол-во записей было равно количеству записей в справочнике  (azs)
4. При несовпадении в таблицу (kash)  копируются записи из справочника (azs)  с добавлением параметра ДАТА из компонента на форме.

проблема такая.
Пока не трогаю компонент дата (не меняю дату) скрипт работает.
Как только меняю дату скрипт ведет себя странно - перестает выполняться проверка условия
if t<  SQLExecute('SELECT count(id) FROM azs ;') then
то есть даже если количество записей в таблице (kash) равняется количеству записей в таблице  (azs)  дальнейшие процедуры все равно выполняются и происходит задваивание записей.
Причем после закрытия базы и повторному открытии - на внесенные даты это условие работает нормально. но на новые даты опять ведет также
Подскажите что не так

Чучкин Евгений

Re: Есть реальная проблема со скриптом

Приветствую,


К сожалению я не могу помочь с алгоритмом, я могу помочь только с конкретным вопросом.

Dmitry.

3 (edited by iacovlogica 2016-03-16 19:47:17)

Re: Есть реальная проблема со скриптом

DriveSoft wrote:

Приветствую,


К сожалению я не могу помочь с алгоритмом, я могу помочь только с конкретным вопросом.

Дмитрий здравствуйте !
Посчитав задачу интересной я хотел человеку помочь и напоролся на баг (ИМХО)
задача состояла в том что бы из таблицы выбрать записи с определенной датой ( я сделал по диапазону дат ) и скопировать эти записи в ту же таблицу но заменив дату на указанную в датетаймпикчере

первая реализация состояла в том чтоб сперва SQL запросом заполнить таблгрид и от туда в цикле от количества записей их скопировать обратно в таблицу с заменой даты. ( работает полностью так как задумано )

Вторая реализация состояла из того что вместо таблгрида я использовал класс TDataSet и тут я вчера вынес себе мозг.....
Проблема состояла в том что вместо того чтоб произвести ОДНУ новую запись SQL запрос уходил в вечную циклическую запись одинаковых строк .
Путем нескольких экспериментов я установил что если вместо даты в запрос скармливать любой текст то все работает так как нужно единственно что вместо даты будет текст , НО если в запрос вставить дату в ТЕКСТОВОМ виде запрос уходит в нирвану .....

Первая реализация:

procedure zakazi_Primenit_OnClick (Sender: string; var Cancel: boolean);
var
i : integer ;
begin
 for i := 0 to zakazi.Tabl.RowCount -1 do
  begin
   SQLExecute('INSERT INTO sobitiya ( data , sobitie ) VALUES ('+zakazi.Ust.sqlDateTime+', '+chr(39)+ zakazi.Tabl.Cells[2,i]+chr(39)+' )');
  end;
  zakazi.Pokazati.Click ;
end;

Вторая реализация : ( Которая уходит в нирвану)

procedure zakazi_Button1_OnClick (Sender: string; var Cancel: boolean);  // Через TDataSet
var
    PromTabl : TDataSet;  // Объявляем класс TDataSet
begin
    // Заполняем класс данными по условию между двух дат (Заполняет корректно)
    SQLQuery('SELECT id ,data ,sobitie FROM sobitiya WHERE data Between '+ zakazi.dtFrom.sqlDateTime+' AND '+ zakazi.dtTo.sqlDateTime ,PromTabl);


    while not PromTabl.Eof do    // Если указатель записи не на конце выполнить

    begin  // Собственно запрос который уходит в бесконечный цикл записи при наличии даты  в тексте  
       SQLExecute('INSERT INTO sobitiya ( data , sobitie ) VALUES ( '+zakazi.Ust.sqlDateTime+', '+chr(39)+PromTabl.FieldByName('sobitie').AsString+chr(39) +' )');

       PromTabl.Next; //  Указатель перемещаем на следующую запись
    end;

    PromTabl.Free;
    zakazi.Pokazati.Click ;
end;

творение прикладываю , нужное закоментил.( сделал в версии 2.4 )
...если кому надо внутри есть и выборка по диапазону дат  и времени и функция преобразования DateTime в строку для SQL с миллисекундами ( передавать надо через текстовое поле )

Post's attachments

Attachment icon kopir.7z 282.5 kb, 394 downloads since 2016-03-16 

Re: Есть реальная проблема со скриптом

суть вопроса проста.
Есть 2 таблицы:
1 справочник АЗС  (azs)
1 таблица с данными (Каsh) где 1 поле - ID_asz (ссылка на запись из справочника АЗС)

В справочнике АЗС - количество записей - вагон и маленька тележка (около 300).
В таблицу с данными нужно ЕЖЕДНЕВНО (в рабочие дни) вносить записи с данными по всем АЗС (ежедневно по 300 записей) в каждой записи по 16 колонок (полей) которые нужно заполнять. и пара полей впомогательных
Понимаете как это не легко 1 человеку ежедневно вносить около 5000 полей да сперва еще не забыть кого нибудь создать каждый день

Дабы облегчить труд я решил создавать записи автоматом (по карйнем мере в приложенном скрипте создаются все записи на новую дату из справочника АЗС правда с пустыми полями остальными. но самое главное что  в таблице на главном окне выходят все АЗС на заданную дату и при заполнении уже самих данных (16 полей) эта запись переходит из 1 таблицы в другую (чекбокс - данные введены). И оператору остается только успеть зайти во все таблицы.
Вобщем то задача решена. скрипт работает.
Но как только в процессе работы мы изменяем базовый справочник  (добавляем новую АЗС) то скрипт начинает вести себя криво. Если же после добавления АЗС выйти из программы и заново зайти то все нормально.

Это была первая часть проблемы.
Вторая часть проблемы немного пересекается с первой.
Данные по ценам на АЗС меняются не каждый день
И желательно при создании записей на новую дату чтобы данные переносились из предыдущей даты, а потом уже оператор просматривая записи менял где надо на новую дату и ставил галочку в чекбоксе что данные введены.
В идеале вторую задачу надо совместить с первой но пока первая еще не корректно работает.

Чучкин Евгений

Re: Есть реальная проблема со скриптом

прямо какая то засада с написанием этого скрипта.

Решил пойти путем сложным путем введя 16 переменных и добавляя записи с помощью цикла.
Мало того что это получилось муторно, так как изначально значения числовые а Insert into работает с текстовыми значениями и пришлось делать 32 переменных, так еще и пролбема потом выскочила когда значение было не целое а дробное с запятой.
При трансформации получился текст "к примеру - 32,54" и при вставке переменной в новую запись прога воспринимает его как 2 значения 32 и 54 и ругается на несопоставиме количество столбцов из базовой записи и новой записи. При целых числах - все нормально

Плюнул на все. создал дублирующую таблицу и попытался создать в ней записи
SQLExecute('insert into kash1 SELECT * FROM kash WHERE date ='+D1+' and id='+azstext+'');
и опять чтото ругается
Unique constraint failed  kash1.id

Чучкин Евгений

Re: Есть реальная проблема со скриптом

Суть задачи понятна хотя вы нераскрыли полностью сути проблемы.
...но остались вопросы
1. Какова временнАя актуальность таблицы кэш ? ( день , месяц , год  ? и нужно ли ее хранить или она меняется каждый день ? )
2. Каким способом происходит сбор данных такого объема ?
3. Зачем вам хранить числа как числа ? Они будут еще где-то использоваться ?
4. Почему бы не сделать редактирование прямо в таблгриде ? ( можно поизвращаться немного но это думаю реализуемо )

Re: Есть реальная проблема со скриптом

1. Временная актуальность таблицы КЭШ как минимум год
2. Сбор данных проходит по телефону, факсу, электронной почте - источники разные
3. Числа нужны для формирования отчета (это еще 1 трабла) - там выходных форм несколько и используются максимальные и минимальные занчения в разрезе муниципалитетов, средние значения по организации и муниципалитету, сравнение с 2-я датами (как парвило сравнивается неделя и декада)
4. количесвто строк и колонок в таблгриде будет много и неудобно.

Я вроде нащупал решение но пока до конца не реализовал.
1. В момент репликации данных определил максимальную ID из таблицы КЭШ (реализовано)
idkash:= SQLExecute('SELECT max(id) FROM kash ;') ;//определяем максимальныую УН запись в данных

2. Создал дубликаты записей из таблицы КЭШ туда же за опредленную дату через цикл (реализовано)
for azsx:=1 to azs do // цикл создания записей начиная с 1-й записи в справочнике АЗС и заканчивая последней
    begin
    azstext:=VarToStr (azsx);
    if SQLExecute('SELECT count(id) FROM azs WHERE id='+azstext+'') = 1 then
    begin
    SQLExecute('insert into kash (id_azs,date,gotov,Z_A80) SELECT id_azs,date,gotov,Z_A80  FROM kash WHERE date ='+D1+' and id='+azstext+'');
    UpdateDatabase('kash');
    end else
    ShowMessage ('В справочнике АЗС нет такого УН');
    end;

3. Осталось обновить дату у записей имеющих ID> idkash: (пока не реализовано)
SQLExecute('update kash SET date = '+D2+'');

надо добавить условие только но чего то не получается. в идеале по SQL должно выглядеть так
update kash SET date = '+D2+'' where id>idkash.
в том виде какая работает - обновление идет у всех записей из таблицы

Чучкин Евгений

8 (edited by iacovlogica 2016-03-17 11:18:52)

Re: Есть реальная проблема со скриптом

'update kash SET date = '+D2+'where id IN (select id from kash where id>'+idkash+' )'

Re: Есть реальная проблема со скриптом

Вроде заработало. Репликация данных при нажатии кнопки при наличии двух дат на форме


procedure rep_button1_OnClick (Sender: string; var Cancel: boolean);
var
D1, D2: string; //даты 1 и 2
azs: integer;//количество записей в справочнике АЗС
idkash,azsx: integer;//переменная - УН записи АЗС
idkash1, azstext: string;
begin
D1 := '"'+ FormatDateTime('yyyy-MM-DD 00:00:00.000',  (rep.DateTimePicker1.DateTime)) + '"';
D2 := '"'+ FormatDateTime('yyyy-MM-DD 00:00:00.000',  (rep.DateTimePicker2.DateTime)) + '"';
SQLExecute('delete from kash where date = '+D2+'') ;
azs:= SQLExecute('SELECT max(id) FROM azs ;') ;//определяем максимальныую УН запись в справочнике АЗС для составления цикла
idkash:= SQLExecute('SELECT max(id) FROM kash ;') ;//определяем максимальныую УН запись в данных
for azsx:=1 to azs do // цикл создания записей начиная с 1-й записи в справочнике АЗС и заканчивая последней
    begin
    azstext:=VarToStr (azsx);
    if SQLExecute('SELECT count(id) FROM azs WHERE id='+azstext+'') = 1 then
    begin
    SQLExecute('insert into kash (id_azs,date,gotov,Z_A80) SELECT id_azs,date,gotov,Z_A80  FROM kash WHERE date ='+D1+' and id='+azstext+'');
    UpdateDatabase('kash');
    end else
    ShowMessage ('В справочнике АЗС нет такого УН');
    end;
idkash1:=VarToStr (idkash);
SQLExecute('update kash SET date = '+D2+' where id>'+idkash1+'');
UpdateDatabase('kash');
end;

Чучкин Евгений

10 (edited by iacovlogica 2016-03-17 14:56:45)

Re: Есть реальная проблема со скриптом

именно такое добавление записи и запрещено дабы не возникло коллизий
SQLExecute('insert into kash (id_azs,date,gotov,Z_A80) SELECT id_azs,date,gotov,Z_A80  FROM kash WHERE date ='+D1+' and id='+azstext+'')

procedure rep_button1_OnClick (Sender: string; var Cancel: boolean);
var
D1, D2: string; //даты 1 и 2    ***где какая ... DataNaUdalenie , DataDlyaZameni ...
azs: integer;//количество записей в справочнике АЗС
idkash,azsx: integer;//переменная - УН записи АЗС
idkash1, azstext: string;
begin
D1 := '"'+ FormatDateTime('yyyy-MM-DD 00:00:00.000',  (rep.DateTimePicker1.DateTime)) + '"';
D2 := '"'+ FormatDateTime('yyyy-MM-DD 00:00:00.000',  (rep.DateTimePicker2.DateTime)) + '"';

SQLExecute('delete from kash where date = '+D2+'') ; // ***Удалить из таблицы КЭШ записи с датами D2 ?  зачем ?

azs:= SQLExecute('SELECT max(id) FROM azs ;') ;//определяем максимальную УН запись в справочнике АЗС для составления цикла

idkash:= SQLExecute('SELECT max(id) FROM kash ;') ;//определяем максимальную УН запись в данных

for azsx:=1 to azs do // цикл создания записей начиная с 1-й записи в справочнике АЗС и заканчивая последней
    begin
        azstext:=VarToStr (azsx);
        if SQLExecute('SELECT count(id) FROM azs WHERE id='+azstext+'') = 1 then  // ***Если количество найденных записей с индексом azsx будет   = 1 ???***
                                                                                  // ***со временем цикл будет расти пропуская удаленные ID
           begin
            SQLExecute('insert into kash (id_azs,date,gotov,Z_A80) SELECT id_azs,date,gotov,Z_A80  FROM kash WHERE date ='+D1+' and id='+azstext+'');  //  ***  Тут полный ахтунг  выборка из КЭШ по ID из AZS ??? возможно id_azs ?

            UpdateDatabase('kash');
           end
        else  ShowMessage ('В справочнике АЗС нет такого УН');
    end;
idkash1:=VarToStr (idkash);
SQLExecute('update kash SET date = '+D2+' where id>'+idkash1+'');
UpdateDatabase('kash');
end;

id_azs это наименование запрвки ?

Re: Есть реальная проблема со скриптом

Вы можете переместить данные из одной таблицы в другую или в туже одним запросом

INSERT INTO table1 ( column1 ) SELECT col1 FROM table2  
Dmitry.

Re: Есть реальная проблема со скриптом

спасибо за совет.
а оно и есть у почти так
вся процедура сводиться к выполнению задачи одной строкой
SQLExecute('insert into kash (id_azs,date,gotov,Z_A80) SELECT id_azs,date,gotov,Z_A80  FROM kash WHERE date ='+D1+' and id='+azstext+'')

все остадбные строки - являются вспомогательными.
Вы же оцениваете толкьо скрипт. я решаю задачу комплексно с учетом иных справочников и возможных багов.
даже сейчас в ходе тестирования вышло несколько неучтенных моментов и скрипт будет не сокращаться а расти smile

Чучкин Евгений