Конференция "Базы" » ADO+ClientDataSet+TThread [D7, Access]
 
  • Alex_C (16.11.11 14:13) [0]
    Чем дальше в лес, тем задачи усложняются.
    Теперь есть такая проблема: получаю из инета пакет около 250 записей. Их надо в отдельном треде получить, обработать и вставить в таблицу. Если вставлять каждую запись через ADODataSet - естественно получается очень долго. По этому я так понимаю нужно использовать ClientDataSet.
    Однако появился вопрос при использовании всей этой связки в отдельном треде:
    когда я пробовал напрямую данные в ADODataSet вставлять, я для каждого треда создавал свой ADOConnectin+ADODataSet в соответствии с рекомендациями.
    Если пытаться создавать еще и TDataSetProvider и TClientDataSet


     ADODataSet1.Active := False;
     ADODataSet1.CommandText := 'SELECT * FROM SpotTable';
     ADODataSet1.Active := True;

     FSpotDataSetProvider := TDataSetProvider.Create(nil);
     FSpotDataSetProvider.DataSet := ADODataSet1;

     FSpotClientDataSet := TClientDataSet.Create(nil);
     FSpotClientDataSet.ProviderName := 'FSpotDataSetProvider';
     FSpotClientDataSet.Open;


    на FSpotClientDataSet.Open; выходит сообщение
    'Missing data provider or data packet'.
    Хотя когда делал пробное приложение и TDataSetProvider и TClientDataSet клал просто на форму - все работало.
  • Медвежонок Пятачок © (16.11.11 14:29) [1]
    Если вставлять каждую запись через ADODataSet - естественно получается очень долго. По этому я так понимаю нужно использовать ClientDataSet.

    .... который сам по себе не умеет ничего и никуда вставлять, а действует через посердников. Так откуда вдруг возьмется быстрота?
  • Медвежонок Пятачок © (16.11.11 14:31) [2]
    //ADODataSet1.CommandText := 'SELECT * FROM SpotTable';
    AdoCommand.CommandText := 'insert into SpotTable() values()';
  • Alex_C (16.11.11 14:45) [3]

    > AdoCommand.CommandText := 'insert into SpotTable() values()';


    Я именно так и вставлял.
    Приведенный пример - из пробной программы. Я пытался подсоединиться к ADODataSet при Runtime создании ClientDataSet.
  • Медвежонок Пятачок © (16.11.11 14:46) [4]
    Ну и кроме того, провайдер в рантайме устанавливается не через свойство, а через метод.
  • Медвежонок Пятачок © (16.11.11 14:47) [5]
    Я именно так и вставлял.

    а это зачем здесь написал:
    ADODataSet1.CommandText := 'SELECT * FROM SpotTable';
  • Alex_C (16.11.11 14:47) [6]
    Еще поясню: вообще мне эти полученные данные нужно по хорошему все время работы программы в памяти держать, только при завершении работы записывать их в таблицу.
  • Alex_C (16.11.11 14:48) [7]

    > ADODataSet1.CommandText := 'SELECT * FROM SpotTable';


    Это пробовал вообще связка ADO+ClientDataSet работает или нет. Если ClientDataSet на форму класть - работает. Сздавать в рантайм - нет.
  • Медвежонок Пятачок © (16.11.11 14:49) [8]
    Но логика просто вне границ постижимого.

    "Датасет вставляет медленно, значит прикрутим к нему клиентдатасет. Датасет после этого испугается и начнет вставлять на форсаже".
  • Alex_C (16.11.11 14:55) [9]
    Для начала о проблеме - в рантайме при создании ClientDataSet нужно использовать CreateDataSet.


    > Датасет вставляет медленно


    Датасает вставляет данные в таблицу, которая имеет объем мегабайты.


    > клиентдатасет


    Клиентвет - никуда ничено не вставляет. Все содержит в памяти, а к базе обращается когда ему скажешь ApplyUpdate.
    Вот от  куда скорость :)
  • Медвежонок Пятачок © (16.11.11 14:58) [10]
    а к базе обращается когда ему скажешь ApplyUpdate.
    Вот от  куда скорость :)


    Открою тайну.
    Там нет никакой сверх скорости.
    Просто там нет сверх-тормозов, которые есть в твоем алгоритме вставки.

    А так этот аплайапдейт точно также вставляет строку за строкой отдельными инсертами.
  • MsGuns © (16.11.11 15:02) [11]
    >Alex_C   (16.11.11 14:55) [9]
    >Для начала о проблеме - в рантайме при создании ClientDataSet нужно >использовать CreateDataSet.

    Вы по ходу путаете создание экземпляра TClientDataSet и собственно датасета, как "хранилища" данных.
  • MsGuns © (16.11.11 15:06) [12]
    И согласен с медвежонком,- используете TClientDataSet явно не по назначению (для временного хранения табличных данных, например в течение сеанса, обычно используют временные локальные таблицы на сервере, а  память используют для хранилища только в том случае, если "базы вообще нет "под рукой" либо обмен с нею затруднителен (медленный, с обрывами  и т.д.) Ну или в сервере приложений.
  • Inovet © (16.11.11 15:14) [13]
    > [6] Alex_C   (16.11.11 14:47)
    > Еще поясню: вообще мне эти полученные данные нужно по хорошему
    > все время работы программы в памяти держать, только при
    > завершении работы записывать их в таблицу.

    Если их всё равно надо записать, то надо это сджелать как можно быстрее, т.е. сразу при получении. В памяти они и так в Dataset хранятся.


    > [9] Alex_C   (16.11.11 14:55)
    > Датасает вставляет данные в таблицу, которая имеет объем мегабайты.

    Это мелочь.

    Я тебе уже говорил - в запросах желательно пользоваться параметрами.
  • Alex_C (16.11.11 15:15) [14]

    > CreateDataSet


    SetProvider нужно делать при подключении к новому провайдеру - эта проблема решена.


    > TClientDataSet явно не по назначению


    Сейчас второй час читаю статьи из инета, где везда сказано, что вот как раз для этой цели необходимо использовать TClientDataSet . И везде именно делается акцент на то, что TClientDataSet все делает в памяти.
  • Alex_C (16.11.11 15:19) [15]
    Вот процедура, которой я вставляю данные в таблицу


    procedure InsertSpot(SpotDataSet: TADODataSet;
     DXCall: string; DateSpot, TimeSpot: TDateTime;
     Freq: Double; SpoterCall, Info: string; DateTimeOfGet: TDateTime;
     IsNewCountry: integer; IsNewSpot: Boolean; Country, BandADIF, Mode: string);
    begin
     with SpotDataSet do
     begin
       CommandText := 'INSERT INTO SpotTable (DXCall,DateSpot,TimeSpot,Freq,' +
         'SpoterCall,Info,DateTimeOfGet,IsNewCountry,IsNewSpot,Country,BandADIF,Mode) ' +
       'VALUES(:DXCall,:DateSpot,:TimeSpot,:Freq,:SpoterCall,:Info,:DateTimeOfGet,' +
       ':IsNewCountry,:IsNewSpot,:Country,:BandADIF,:Mode)';
       Parameters.ParamByName('DXCall').Value := DXCall;
       Parameters.ParamByName('DateSpot').Value := DateSpot;
       Parameters.ParamByName('TimeSpot').Value := TimeSpot;
       Parameters.ParamByName('Freq').Value := Freq;
       Parameters.ParamByName('SpoterCall').Value := SpoterCall;
       Parameters.ParamByName('Info').Value := Info;
       Parameters.ParamByName('DateTimeOfGet').Value := DateTimeOfGet;
       Parameters.ParamByName('IsNewCountry').Value := IsNewCountry;
       Parameters.ParamByName('IsNewSpot').Value := IsNewSpot;
       Parameters.ParamByName('Country').Value := Country;
       Parameters.ParamByName('BandADIF').Value := BandADIF;
       Parameters.ParamByName('Mode').Value := Mode;
       Execute;
     end;
    end;



    На вставку 250 записей уходит порядка 5-8 сек. У знакомого, проф программиста, использующего практически все тоже самое, все вставляется мгновенно. Спросил почему? Ответ был ClientDataSet.
    Опять же - читаю что в инете пишут. Все тоже - использовать ClientDataSet.
  • Медвежонок Пятачок © (16.11.11 15:19) [16]
    что вот как раз для этой цели необходимо использовать TClientDataSet

    Для какой "этой" цели?
  • Медвежонок Пятачок © (16.11.11 15:28) [17]
    with SpotDataSet do
    begin
      CommandText := 'INSERT INTO SpotTable (DXCall,DateSpot,TimeSpot,Freq,' +
        'SpoterCall,Info,DateTimeOfGet,IsNewCountry,IsNewSpot,Country,BandADIF,Mode) '


    Львиная доля времени из всех 5-8 секунд здесь уходит на перечитывание метаданных и строительство списка переметров.
    Что у проф программиста отсутствует.
  • Медвежонок Пятачок © (16.11.11 15:29) [18]
    .... И делается это тупое бесполезное дело все двести пятьдесят раз.
  • Alex_C (16.11.11 15:29) [19]
    В общем вы все конечно правы :)
    Не поленился, сделал все с ClientDataSet - скорость точно такая же, как и с одним ADOCommand - скорость вставки ничем не отличается.


    > Для какой "этой" цели?


    Цель - создание временной, максимально быстрой таблицы в памяти, количество записей - менее 500. Нужна максимально быстрая вставка и выборка. Вставка производится из нескольких потоков (т.е. таблица должна быть потокозащищенной).
    Вот как то так))
  • Alex_C (16.11.11 15:32) [20]

    > AdoCommand.CommandText := 'insert into SpotTable() values()';


    > Львиная доля времени из всех 5-8 секунд здесь уходит на
    > перечитывание метаданных и строительство списка переметров.
    >
    > Что у проф программиста отсутствует.
    >


    Чего то я не понял. В [2] ты ж сам так предлагаешь делать?


    > Что у проф программиста отсутствует.


    Я и не являюсь проф программистом. По улицам на машинах не только же проф гонщики ездиют :)
  • Медвежонок Пятачок © (16.11.11 15:37) [21]
    Чего то я не понял. В [2] ты ж сам так предлагаешь делать?

    серьезно?
    я тебе предлагал двести пятьдесят раз подряд чистить текст sql заменяя его не него же для того, чтобы датасет двести пятьдесят раз перечитал метаданные одной и той же таблицы?
  • Inovet © (16.11.11 15:43) [22]
    > [20] Alex_C   (16.11.11 15:32)
    > > Что у проф программиста отсутствует.
    >
    > Чего то я не понял. В [2] ты ж сам так предлагаешь делать?

    И в третий раз повторю, раз предыдущие игнорируешь игнорируешь.

    > [13] Inovet ©   (16.11.11 15:14)
    > Я тебе уже говорил - в запросах желательно пользоваться
    > параметрами.
  • Alex_C (16.11.11 15:56) [23]

    > я тебе предлагал двести пятьдесят раз подряд чистить текст
    > sql заменяя его не него же для того


    > И в третий раз повторю, раз предыдущие игнорируешь игнорируешь.
    >
    >
    > > [13] Inovet ©   (16.11.11 15:14)
    > > Я тебе уже говорил - в запросах желательно пользоваться
    > > параметрами.


    Я понимаю, что я чего то не понимаю. А вот чего я не  понимаю - я не понимаю. :)
    Я думал, что "пользоваться параметрами" это


    ParamByName('IsNewCountry').Value := IsNewCountry;



    сейчас я понимаю, что я не правильно истолковал сию фразу.  Тогда что понимается под фразой - использовать параметры?
  • Alex_C (16.11.11 16:05) [24]

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


    С этим я разобрался - понял, что AdoCommand.CommandText - пишется один раз, потом просто подставляются параметры. Переделал - особо быстро все равно не стало.
  • Медвежонок Пятачок © (16.11.11 16:08) [25]
    Насколько особо быстро надо?

    При учете того, что вставка будет не в главном потоке, а данные из физической таблицы в приложении не используются.
  • Alex_C (16.11.11 16:19) [26]

    > При учете того, что вставка будет не в главном потоке, а
    > данные из физической таблицы в приложении не используются.
    >


    В общем наверное я сам себе уже мозги запудрил.

    Как было сделано: у меня была своя импровизированная таблица в памяти - массив, куда я заполнял получившиеся данные, после получения всех данных я их копировал в несколько VolgaTable для различных целей. В принципе все было очень быстро. В связи с переходом основной базы на Access а был приятно поражен возможность выборки данных. Вот и решил, и как сам сейчас понимаю - не удачно применить Access - подкупало что можно выборку делать из одной таблицы. Теперь понял, что так получается куда как медленнее.
  • Медвежонок Пятачок © (16.11.11 16:22) [27]
    у меня была своя импровизированная таблица в памяти - массив

    А она вообще нужна своя?

    получаю из инета пакет около 250 записей.

    В виде чего получаешь из инета?
  • MsGuns © (16.11.11 16:52) [28]
    Вот откуда-то "извне" программа поочередно получает 500 записей, после чего в цикле засовывает их в некую БД. Внимание, вопрос: с какого боку тут многопоточность и что она собсна даст ?
  • Медвежонок Пятачок © (16.11.11 16:56) [29]
    многопоточность здесь даст.
    если скажем пришедший пакет это xml пакет.
    грузим его как есть и используем в приложении как "быструю таблицу в памяти"
    во вторичном потоке неспеша инсертим это в бд.
  • Inovet © (16.11.11 19:19) [30]
    Как-то сильно много 5-8 секунд на 250 записей.
  • Юджин © (16.11.11 19:27) [31]
    Удалено модератором
    Примечание: не спамь
  • Alex_C (16.11.11 21:30) [32]

    > А она вообще нужна своя?
    >


    Получение максимально потокозащищенного кода за счет полного контроля над тем, что делаешь. Только из этих соображений.
    Access меня еще и прельстил потокозащищенностью.


    >  с какого боку тут многопоточность и что она собсна даст
    > ?


    Заставлять пользователя ждать 10 сек получения и сортировки данных? Не думаю, что хорошее решение.


    > В виде чего получаешь из инета?


    Текст. Парсю строки, строки имеют определенный формат.


    > во вторичном потоке неспеша инсертим это


    Да собственно в итоге к этому и пришел.


    > Как-то сильно много 5-8 секунд на 250 записей.


    Много. Совсем забыл, что кроме добавления, каждая пришедшая "запись" - а это информация о работе в эфире редкой станции еще проверяется, есть ли такая страна в логе и на данном диапазоне/моде.
    В итоге - просто вставка - 3 сек. +5 сек запрос к базе лога на предмет подтверждения страны.
    В принципе думаю на это пока забить - даже фоновая задержка получения начального пакета из 250 последних спотов - не проблема. После этого споты будут приходить по одному через телнет - а это уже доли секунды на обработку.
  • Inovet © (16.11.11 22:16) [33]
    > [32] Alex_C   (16.11.11 21:30)
    > кроме добавления, каждая пришедшая "запись" - а это информация
    > о работе в эфире редкой станции еще проверяется, есть ли
    > такая страна в логе и на данном диапазоне/моде.

    Вообще-то этим должен заниматься движок БД, а приложение должно только обработать исключение в случае неудачи.
  • Alex_C (16.11.11 22:48) [34]

    > Вообще-то этим должен заниматься движок БД


    Сейчас подешел к изучению хранимых процедур.
    Как я понимаю, этим должны заниматься именно они.
    Я правильно понимаю направление?
  • Inovet © (16.11.11 23:33) [35]
    > [34] Alex_C   (16.11.11 22:48)
    > Сейчас подешел к изучению хранимых процедур.
    > Как я понимаю, этим должны заниматься именно они.

    Как там в аксесе с еими не знаю. Они в более сложных случаях, а для проверки по справочнику достаточно внешнего ключа. Да я уже много раз говорил об этом.
  • sniknik © (17.11.11 00:00) [36]
    никто никому ничего не должен... нужна процедура? вот тебе лично - делай процедурой.
    а вообще хватило бы запроса с джойном. (как понял описание чего нужно)

    p.s. начинать изучение процедур с аксесса... плохая идея. нет их там практически, одно название.
  • Alex_C (17.11.11 08:43) [37]

    > вообще хватило бы запроса с джойном.


    Вот сейчас как раз ломаю над этим голову. Как я понимаю, можно все же обойтись и одним запросом.
  • Alex_C (17.11.11 09:42) [38]
    Вопрос по св-ву ExecuteOptions для ADOCommand - после вставки 250 записей, мне нужно удалить повторы. Если комманду удаления повторов я ставлю сразу после комманды вставки - удаления не происходит. Если делать вручную - при нажатии на кнопку - повторы удаляются. Я так понимаю, что это происходит из-за того, что сама таблица после повторов не успела обновиться.
    Ставил
    ExecuteOptions := [eoAsyncExecute];


    начинает ругаться при вставке записей - Не удается выполнить операцию во время асихронного выполнения.
  • Alex_C (17.11.11 09:52) [39]

    > ExecuteOptions := [eoAsyncExecute];


    Разобрался..
  • sniknik © (17.11.11 09:58) [40]
    > после вставки 250 записей, мне нужно удалить повторы.
    может лучше не вставлять повторы? + добавить уникальный индекс по полям, чтобы сама база следила.
  • Alex_C (17.11.11 10:10) [41]

    > может лучше не вставлять повторы


    Мне надо "наоборот" - старый "повтор" тот что в базе - стерся, а на его место новый записался, который кроме полей, которые определяют повтор, содержит еще информативные поля, которые нужно обновить.

    Все же пока не получается удалить повторы сразу за вставкой - если вставлять время ожидания после вставки, а потом удалять, то все ок!
  • sniknik © (17.11.11 10:38) [42]
    > Мне надо "наоборот" ...
    т.е. обходной маневр из-за незнания команды update?
    удачи.

    > Все же пока не получается удалить повторы сразу за вставкой
    асинхронность отключи если есть, и используй 1 коннект если 2.
  • Alex_C (17.11.11 11:00) [43]

    > используй 1 коннект если 2.


    Не могу - данные вставляются в отдельном треде - ему нужен отдельный коннект.


    > обходной маневр из-за незнания команды update?


    мне кажется так дольше получится:


       SELECT DXCall, Freq FROM SpotTable WHERE DXCall=:DXCall AND Freq=:Freq
       if RecordCount > 0 then
         UPDATE
       else
         INSERT



    Чем сначала все записи вставлять, а потом скопом удалять повторы.
  • Anatoly Podgoretsky © (17.11.11 11:10) [44]
    > Alex_C  (17.11.2011 09:42:38)  [38]

    > после вставки 250 записей, мне нужно удалить повторы.

    Подход в корне неверный, не надо добавлять повторы
  • Anatoly Podgoretsky © (17.11.11 11:11) [45]
    > Alex_C  (17.11.2011 10:10:41)  [41]

    Это тоже не требует добавления
  • Медвежонок Пятачок © (17.11.11 11:11) [46]
    AdoCommand

    Call Execute to immediately execute the command specified in the CommandText property.

    RecordsAffected indicates the number of records, if the command operates on data, that are affected by the command after execution.
  • Anatoly Podgoretsky © (17.11.11 11:13) [47]
    > Alex_C  (17.11.2011 11:00:43)  [43]

    Если кажется, крестись
    Ничего удалять не надо
    Кстати логика с запросом неверная, лучше удалить и потом вставлять. Можно
    попытаться вставить и если не получится обновлять - всяко быстрее, кроме
    редких сдучаев
  • Inovet © (17.11.11 11:14) [48]
    > [43] Alex_C   (17.11.11 11:00)
    >   SELECT DXCall, Freq FROM SpotTable WHERE DXCall=:DXCall
    > AND Freq=:Freq
    >   if RecordCount > 0 then
    >     UPDATE
    >   else
    >     INSERT

    Эх. А справку прочитать по UPDATE?
    UPDATE SpotTable SET Freq = :Freq WHERE DXCall=:DXCall AND ...
  • sniknik © (17.11.11 11:54) [49]
    > мне кажется так дольше получится:
    250 записей? человек моргнуть не успеет, не то что как то прореагировать... как ни делай.
    и поток не нужен.

    +
    > Заставлять пользователя ждать 10 сек получения и сортировки данных?
    так где таки тормоза, на получении или сортировке(250 записей???)/вставке? ну так и выноси в поток именно получение... а микросекунды не экономь.
  • Anatoly Podgoretsky © (17.11.11 12:19) [50]
    > sniknik  (17.11.2011 11:54:49)  [49]

    Может лучше разобраться почему такие тормоза при 250 записей?
  • Alex_C (17.11.11 12:22) [51]
    В общем после TTable к SQL переходить тяжеловато :)

    Заработало!))))


             ChangeRecords := 0;
             with FSpotCommand.Parameters, FSpotCommand do
             begin
               CommandText := 'UPDATE SpotTable SET Info=:Info WHERE (DXCall=:DXCall) AND (Freq=:Freq)';
               ParamByName('DXCall').Value := ClusterData.DXCall;
               ParamByName('Freq').Value := ClusterData.Freq;
               ParamByName('Info').Value := ClusterData.Info;
               Execute(ChangeRecords, '');
             end;

             if ChangeRecords = 0 then
               InsertSpot(FSpotCommand, ClusterData.DXCall, Trunc(SpotDate), //Тут вставляем если надо!



    Теперь остался момент по взаимодействию разных ADODataSet - как дождаться удаления записей? Просто хочу очистить таблицу и перечитать ее. В одной ф-ции следать

     DELETE *
     Execute;
     SELECT *
     Execute;


    Не получается - после DELETE надо несколько секунд ждать.
  • sniknik © (17.11.11 13:35) [52]
    > Может лучше разобраться почему такие тормоза при 250 записей?
    ну, там выше вроде упомянуто на получение из инета... вполне нормальные "тормоза" если так.
    вот если бы он сказал, что именно от вставки... тут да.

    > Заработало!))))
    и это пишет "борец с тормозами"... ;) код в цикле выполняется?

    > Теперь остался момент по взаимодействию разных ADODataSet - как дождаться удаления записей?
    читай еще раз [42]
  • Alex_C (17.11.11 14:37) [53]

    > и это пишет "борец с тормозами"... ;) код в цикле выполняется?
    >  


    Блин, ну а как его без цикла то пустить? )))

    Кстати почему то во так не работает

    UPDATE SpotTable SET DateTimeOfGet=:DateTimeOfGet ...



    DateTimeOfGet - тип DateTime. Если менять на другое поле типа стринг

    UPDATE SpotTable SET Info=:Info...



    Все работает. Непонятно.
  • sniknik © (17.11.11 14:54) [54]
    > Блин, ну а как его без цикла то пустить? )))
    имелось ввиду не без цикла, а вынести "за" него бессмысленные внутри "тормозящие" операции... типа внесение запроса, парсинг параметров, оставить только внесение значений и ехекют.

    > Кстати почему то во так не работает
    написано в ошибке.
  • Inovet © (17.11.11 15:04) [55]
    > [54] sniknik ©   (17.11.11 14:54)
    > вынести "за" него бессмысленные внутри "тормозящие" операции...
    > типа внесение запроса, парсинг параметров

    Prepared := true
  • Alex_C (17.11.11 15:15) [56]

    > написано в ошибке.

    Не соответствует тип.
    Проверил - такая ошибка выдается для всех полей типа TDateTime.
  • Alex_C (17.11.11 15:17) [57]

    > вынести "за" него бессмысленные внутри "тормозящие" операции.
    > .


    > Prepared := true

    Тогда придется несколько ADOCommand заводить для UPDATE и отдельно для INSERT. Это правильно?
  • Inovet © (17.11.11 15:19) [58]
    > [56] Alex_C   (17.11.11 15:15)
    > Не соответствует тип.
    > Проверил - такая ошибка выдается для всех полей типа TDateTime.

    Строковое представление зависит от текущей локали, поэтому надо пользоваться параметрами или, если уж приспичило зачем-то строкой с дополнительным тормозои на её разбор, то передавать в каноническом формате. Формат есть в хелпе.
  • Inovet © (17.11.11 15:20) [59]
    > [57] Alex_C   (17.11.11 15:17)
    > Тогда придется несколько ADOCommand заводить для UPDATE
    > и отдельно для INSERT. Это правильно?

    Есть много не просят, отчего бы и не завести сколько надо, раз надо.
  • Alex_C (17.11.11 15:24) [60]
    Ок! Думал что наоборот лучше меньше.

    Однако на счет UPDATE я рано радовался. Как то "странно" он работает.
    Даю комманду
    UPDATE SpotTable SET Info="111" WHERE (DXCall=:DXCall)


    и все поля Info становятся пустыми, вместо 111.
  • Alex_C (17.11.11 15:26) [61]

    > Строковое представление зависит от текущей локали


    Так это я уже понял - в том то и дело - дату как параметр передаю! Вот в чем непонятка. Причем для всех 3-х полей типа даты - одна и таже проблема.
  • Alex_C (17.11.11 15:28) [62]
    Параметры:

     FSpotCommand := TADOCommand.Create(nil);
     with FSpotCommand do
     begin
       Connection := FSpotConnection;
       Parameters.Clear;
       with Parameters.AddParameter do
       begin
         Name := 'DXCall';
         DataType := ftString;
         Direction := pdInput;
         Size := 50;
       end;
       with Parameters.AddParameter do
       begin
         Name := 'DateSpot';
         DataType := ftDate;
         Direction := pdInput;
       end;
       with Parameters.AddParameter do
       begin
         Name := 'TimeSpot';
         DataType := ftTime;
         Direction := pdInput;
       end;
       with Parameters.AddParameter do
       begin
         Name := 'Freq';
         DataType := ftFloat;
         Direction := pdInput;
       end;
       with Parameters.AddParameter do
       begin
         Name := 'SpoterCall';
         DataType := ftString;
         Direction := pdInput;
         Size := 20;
       end;
       with Parameters.AddParameter do
       begin
         Name := 'Info';
         DataType := ftString;
         Direction := pdInput;
         Size := 100;
       end;
       with Parameters.AddParameter do
       begin
         Name := 'DateTimeOfGet';
         DataType := ftDateTime;
         Direction := pdInput;
       end;
       with Parameters.AddParameter do
       begin
         Name := 'IsNewCountry';
         DataType := ftInteger;
         Direction := pdInput;
       end;
       with Parameters.AddParameter do
       begin
         Name := 'IsNewSpot';
         DataType := ftBoolean;
         Direction := pdInput;
       end;
       with Parameters.AddParameter do
       begin
         Name := 'Country';
         DataType := ftString;
         Direction := pdInput;
         Size := 10;
       end;
       with Parameters.AddParameter do
       begin
         Name := 'BandADIF';
         DataType := ftString;
         Direction := pdInput;
         Size := 20;
       end;
       with Parameters.AddParameter do
       begin
         Name := 'Mode';
         DataType := ftString;
         Direction := pdInput;
         Size := 20;
       end;




            with FSpotCommand.Parameters, FSpotCommand do
            begin
              CommandText := 'UPDATE SpotTable SET Info=:Info WHERE (DXCall=:DXCall) ' +
               'AND (DateSpot=:DateSpot) AND (TimeSpot=:TimeSpot) ' +
               ' AND (Freq=:Freq) AND (SpoterCall=:SpoterCall)';
              ParamByName('DXCall').Value := ClusterData.DXCall;
              ParamByName('DateSpot').Value := Trunc(SpotDate);
              ParamByName('TimeSpot').Value := Frac(SpotDate);
              ParamByName('Freq').Value := ClusterData.Freq;
              ParamByName('Info').Value := ClusterData.Info;
              ParamByName('SpoterCall').Value := ClusterData.SpoterCall;
              Execute(ChangeRecords, '');
            end;

  • Alex_C (17.11.11 15:31) [63]
    Убираем параметры даты/времени - все работает.... относительно работает... поле Info становится пустым.
  • Inovet © (17.11.11 15:45) [64]
    > [62] Alex_C   (17.11.11 15:28)
    > ParamByName('DateSpot').Value := Trunc(SpotDate);
    > ParamByName('TimeSpot').Value := Frac(SpotDate);

    ParamByName('DateSpot').AsDateTime := StartOfTheDay(SpotDate);
    ParamByName('TimeSpot').AsDateTime := Frac(SpotDate);

    И зачем ты оставил всё-таки два поля? Есть реальная необходимость?

    Непонятно что там с Info.
  • Alex_C (17.11.11 16:00) [65]

    > И зачем ты оставил всё-таки два поля? Есть реальная необходимость?


    Есть некоторая, можно и одно сделать - это из прошлой программы осталось. Мне белее не понятно, почему с DateTime проблемы.


    > ParamByName('DateSpot').AsDateTime := StartOfTheDay(SpotDate);


    Это

    function StartOfTheDay(const AValue: TDateTime): TDateTime;
    begin
     Result := Trunc(AValue);
    end;

  • sniknik © (17.11.11 16:23) [66]
    ftDate - ftDateTime
    ftTime - ftDateTime

    не все понимают "огрызки".

    > почему с DateTime проблемы.
    с ним то как раз проблем нет, а у тебя что?
  • Alex_C (17.11.11 16:33) [67]
    Так. Первую проблему нашел -

    ParamByName('TimeSpot').AsDateTime := Frac(SpotDate);


    Так нельзя.

    По ходу

    > не все понимают "огрызки".

    Нельзя давать отдельно дату и отдельно время.
  • Alex_C (17.11.11 16:49) [68]
    Нашел следующую проблему с UPDATE:


    UPDATE SpotTable SET DateTimeSpot=:DateTimeSpot


    В SET не получается использовать тип DateTime.
  • Alex_C (17.11.11 16:56) [69]

    > В SET не получается использовать тип DateTime.

    Сделал сейчас пробную отдельную программу - все работает..
    Почему же у меня не работает


    procedure UpdateSpot(var SpotCommand: TADOCommand;
     DXCall: string; DateTimeSpot: TDateTime;
     Freq: Double; SpoterCall, Info: string; DateTimeOfGet: TDateTime);
    begin
     with SpotCommand.Parameters, SpotCommand do
     begin
       ParamByName('DXCall').Value := DXCall;
       ParamByName('DateTimeSpot').Value := DateTimeSpot;
       ParamByName('Freq').Value := Freq;
       ParamByName('SpoterCall').Value := SpoterCall;
       ParamByName('Info').Value := Info;
       ParamByName('DateTimeOfGet').Value := DateTimeOfGet;
       Execute(ChangeRecords, '');
     end;
    end;



    Вызываю

             UpdateSpot(FUpdateSpotCommand, ClusterData.DXCall, SpotDate,
               ClusterData.Freq, ClusterData.SpoterCall,
               ClusterData.Info, Now{MinSpotDate});



    Уже вместо MinSpotDate просто Now поставил... Все равно несоответствие типов.
    Сама CommandText

       CommandText := 'UPDATE SpotTable SET DateTimeOfGet=:DateTimeOfGet ' +
         'WHERE (DXCall=:DXCall) AND (DateTimeSpot=:DateTimeSpot) ' +
         'AND (Freq=:Freq) AND (SpoterCall=:SpoterCall) AND (Info=:Info)';

  • Inovet © (17.11.11 17:25) [70]
    > [69] Alex_C   (17.11.11 16:56)
    > Почему же у меня не работает

    Определение таблицы покажи. Реальное только.
  • Anatoly Podgoretsky © (17.11.11 17:48) [71]

    > Alex_C   (17.11.11 16:00) [65]

    Не используй свойства AS
  • Anatoly Podgoretsky © (17.11.11 17:48) [72]
    > Alex_C  (17.11.2011 16:33:07)  [67]

    Можно
  • Anatoly Podgoretsky © (17.11.11 17:49) [73]
    > Alex_C  (17.11.2011 16:49:08)  [68]

    Чей тип DateTime?
  • Anatoly Podgoretsky © (17.11.11 17:50) [74]
    > Alex_C  (17.11.2011 16:56:09)  [69]

    Да брось ты эти базы, пойди пивка выпей
  • Anatoly Podgoretsky © (17.11.11 17:52) [75]

    > :DateTimeSpot

    Разве Акцесс такие имена понимает
  • Alex_C (17.11.11 22:30) [76]

    > Можно


    Я чего то окончательно запутался. Честно говоря не думал, что организовать работу более 100 радиостанций с разным интерфейсом через ком-порт без практически документации будет проще, чем со связкой SQL+ADO разобраться. ))) Причем на сколько я понимаю, проблема не в SQL, а именно в ADO.


    > Не используй свойства AS


    Так я его и не использую.


    > Разве Акцесс такие имена понимает


    Понимает.


    > Определение таблицы покажи. Реальное только.


    Саму таблицу я создал в эксесе - конструкторе таблиц. Смысла программно ее создавать пока не было, пока окончательно все проблемы не решу.

    Большое спасибо за столь активную мне помощь - очень со многими весьма мало документированными вещами разобрался.
    Однако проблема по ходу не в неправильности SQL запросов как таковых, а в связке с ADO.
    Типичный пример - у меня было поле Band - так эксес его воспринемать не хочет, ругается. Хотя это не зарезервированное поле SQL.
    В общем пока пробую и так, и так - пытаюсь понять суть проблемы.
  • Inovet © (17.11.11 23:34) [77]
    > [76] Alex_C   (17.11.11 22:30)
    > Однако проблема по ходу не в неправильности SQL запросов
    > как таковых, а в связке с ADO.

    Ты через ADO можешь ведь не только к Аксес, который не Аксес а Jet, обращаться, но и к другим серверам, Jet не сервер.
  • Inovet © (17.11.11 23:35) [78]
    > [77] Inovet ©   (17.11.11 23:34)
    > но и к другим серверам

    У них и SQL отличается, и может сильно отличаться.
  • Alex_C (18.11.11 00:10) [79]
    А причину то я нашел - Execute(ChangeRecords, ''); - вот она!
    Нельзя Paramerts в "" устанавливать!
    Вообще вот по этому нет документации!
  • sniknik © (18.11.11 00:49) [80]
    а вот это откуда?
    Parameters   Optional. A Variant array of parameter values passed with an SQL statement. (Output parameters will not return correct values when passed in this argument.)
    или тебе нужен полный список того чего нельзя туда пихать, вместо одного чем является...  только потому что "нарвался" на это.
  • Anatoly Podgoretsky © (18.11.11 09:51) [81]
    > Alex_C  (17.11.2011 22:30:16)  [76]

    Врешь
  • sniknik © (18.11.11 10:25) [82]
    > Врешь
    c Band-ом нет, это группа/линия, что то из функция вызуал бейсика в общем. а jet его поддерживает, частично. но в ограничения в хелпе (моей версии во всяком случае) не все попало/есть путаница.

    а вот с
    > проблема не в SQL, а именно в ADO.
    да, врет. проблема не в ADO, а в непонимании, что такое ADO, того что он чаще всего и не работает сам, а транслирует на конкретный движок в одну сторону, и проблемы его обратно... (как и ODBC/BDE(scllinks)/... другие "объединялки")
    а всего/вариантов так много, что поддержать/перевести абсолютно все не получится.
  • Alex_C (18.11.11 12:19) [83]

    > Parameters   Optional. A Variant array of parameter values
    > passed with an SQL statement. (Output parameters will not
    > return correct values when passed in this argument.)


    Я вчера до поздней ночи перерывал весь инет с надеждой найти как правильно там указывать весь СПИСОК значений параметров - нет нигде. Один - указывается. Группой - никак не получается.
  • Alex_C (18.11.11 12:23) [84]

    > ftDate - ftDateTime
    > ftTime - ftDateTime
    >
    > не все понимают "огрызки".


    С этим тоже разобрался - при присвоении значений полям типа DateTime необходимо явно указывать приведение типа к Дельфийскому TDateTime. Т.е. если хотим, чтоб указывалась ТОЛЬКО дате, нужно делать так:
    TDateTime(Trunc(ValueDateTime)).

    Хорошооооооооо))
    Программа движется)))
  • Alex_C (18.11.11 16:59) [85]
    Мне из полученных значений DX-станций нужно выбрать все "неодинаковые". Неодинакове записи - это если позывной + частота разные, причем частота должна быть +-
    Делаю такой запрос:

       CommandText := 'SELECT P.* FROM SpotTable P WHERE NOT EXISTS ' +
         '(SELECT * FROM SpotTable R WHERE P.DXCall = R.DXCall AND ' +
         '(ABS(P.Freq - R.Freq) < :FreqDelta) AND P.Id < R.Id)';


    В результате - если частота одинаковая, то отображается как и надо, только один спот на данную станцию. А вот если разброс меньше FreqDelta - условие ABS(P.Freq - R.Freq) < :FreqDelta не срабатывает.
    Чего не так?
  • Cobalt © (22.11.11 17:00) [86]
    сделай доп. поле, или вычислимое, в котором будет "позывной + частота"
    и по этому полю
    select distinct MyNewfield

 
Конференция "Базы" » ADO+ClientDataSet+TThread [D7, Access]
Есть новые Нет новых   [134431   +10][b:0.001][p:0.007]