Главная страница
    Top.Mail.Ru    Яндекс.Метрика
Форум: "Базы";
Текущий архив: 2008.06.22;
Скачать: [xml.tar.bz2];

Вниз

Непонятки с ADO или OLE DB   Найти похожие ветки 

 
DeadMeat   (2008-01-17 23:49) [0]

Здравсте.
Вот какая бяка приключилась. Работаю с Turbo Delphi Pro + DevExpress + ADO + MSSQL 2005.
На форме лежит компонент TcxDateTime. В нем выбирают только дату. Времени там нет.
Выбранная дата передается в качестве значения параметра для вызова ХП. Выбирал я ее через свойство EditValue.
Все вроде бы хорошо. Вот тока выяснилось, что если через Студию (Managment Studio) вызвать эту же ХП с этой же датой, результат другой. Начали разбираться.
Запустил профайлер и протреисил что передается серверу. Оказалось, что в ХП передавалась не та дата, которую выбрали, а на один день вперед.
В начале я офигел. Потом решил глянуть, что же выдает EditValue. Офигел во второй раз, когда увидел нечто вида: 01.12.2007 23:59:59.
Т.е. он к дате добавил еще и время. Ну это ладно.. Ведь тип TDateTime и по идее без времени он не идет. Параметр в ХП тоже имеет тип DateTime.
Ну черт с ним со временем, но почему в ХП пришла дата на один день вперед? Кто и как ее "округлил"?
Вызов ХП был через TADOCommand, с передачей параметра через Parameters.
Кто сталкивался? Не думаю, что тут DevExpress виноваты. Скорее либо ADO, либо драйвер... Но это только догадки.


 
sniknik ©   (2008-01-18 00:20) [1]

> Но это только догадки.
именно, догадки, т.к. виноват на самом деле ты... недостаток твоих знаний.

например
> В нем выбирают только дату. Времени там нет.
с чего решил что времени нет? тип дататайм. значит время там по любому присутствует, хоть в виде атавизма,  и если явно не обнулил значит там случайное число (на самом деле подставляется текущее в момент положения компонента на форму, во всяком случае в стандартном так).

по дате... разница в датах есть, на 2 дня (точка отсчета (0) в дельфи с 30.12.1899 в mssql  01.01.1900) но никаких проблем это не создает, т.к. ADO/Delphi/х.з. кто там в цепочке... приводит значение к нормальному, если конечно распознает что это дата в параметре... но некоторые деятели с большим ... э, умом, не пользуются параметрами, не пользуются типами и т.д. (не знаю что там у тебя, код ты как всегда в праведном возмущении посчитал излишним... свой код, а не тех на кого "грешишь" ), вместо подставляют числа туда где должна быть дата... "забывая" естественно сделать тоже что делает ADO (ну раз уж взяли на себя функцию, то не половину а всю). а то еще и строкой передают и т.д.

кстати а DevExpress это эталон? за что это ему такое доверие больше чем ADO, его же используют на порядки меньше людей чем ADO (хотя бы потому что его не только в дельфи используют), и уже много лет, долго тестили в общем... и тут пришел DeadMeat и открыл всем глаза, оно оказывается глючное. о как. я в шоке.


 
DeadMeat ©   (2008-01-18 15:37) [2]

Эмм...

> Ну это ладно.. Ведь тип TDateTime и по идее без времени
> он не идет.

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

Код...
 with dmDBData do
   begin
     ExecuteCommand(dbCommand, "EXEC :outKwt = dbo.fn_Money_to_kWt :inMoney, :inMainCode, :inCounterCode, :inInputDate",
                               "",
                               VarArrayOf([0,
                                           edOplata.Text,
                                           AbonTable.FieldByName("Code").Value,
                                           AbonTable.FieldByName("CurCounterCode").Value,
                                           edPlategDate.EditValue]));
     cxTextEdit1.EditValue := dbCommand.Parameters.ParamByName("outKwt").Value;
   end;

ХП не моя... я лишь пользуюсь тем, что мне дал другой.... прогер.

Вот сама ExecuteCommand:
function ExecuteCommand(var cmd: TADOCommand; sql: string; search: string; par: variant): _Recordset;
var
 i: integer;
begin
 with cmd do
   begin
     CommandText := sql + " " + search;
     for i := 0 to Parameters.Count - 1 do
       Parameters.Items[i].Value := par[i];
     Result := Execute;
   end;
end;

Сделал так для упрощения... Т.к. вызывается много разных ХП и не только.. И селекты делаются.. и Апдейты.. Все хотел сделать более-менее одним способом. search: string осталось от прежней поделки.. До этого юзалось чисто для селектов.. и search использовался еще отдельно. Лень было писать целый парсер. Легче было условия отдельно передать.
Если Вы мне скажите, что надо ВСЕГДА выставлять тип для КАЖДОГО параметра, то получится, что надо делать отдельный ADOCommand для каждой ХП чтоли? Или как?

И на счет эталона... Я нигде не упоминал, что это пуп земли. И о доверии как то странно звучит.. Не делаю я предпочтений между компонентами интерфейса пользователя и компонентами доступа к БД. Указал я про DevExpress


 
DeadMeat ©   (2008-01-18 15:38) [3]

Блин... Нажал случайно..
Так вот..
Указал я про DevExpress исключительно для справки.. Может в нем ошибка и сталкивался кто.. Себя я никогда не исключаю из разряда лам и всегда готов учиться.


 
sniknik ©   (2008-01-18 17:16) [4]

> что надо ВСЕГДА выставлять тип для КАЖДОГО параметра
если он неопределен (т.е. обычно первое присвоение), то устанавливается по типу присваиваемого значения.
а вообще да, если не уверен то тип нужно указывать явно.
в твоем варианте нужно вместо edPlategDate.EditValue edPlategDate.asDateTime, да и то неуверен... у тебя же через вариант дальше передается, а как оно с него считает тип не уверен (не пробовал ни разу).
вообще странная конструкция..., никакого преимущества/экономии кода/времени перед стандартным...
with dmDBData, dbCommand.Parameters do
  begin
    dbCommand.CommandText:= "EXEC :outKwt = dbo.fn_Money_to_kWt :inMoney, :inMainCode, :inCounterCode, :inInputDate";
    //ParamByName("outKwt").Value         := 0; //вряд ли нужно
    ParamByName("inMoney").Value        := edOplata.Text;
    ParamByName("inMainCode").Value    := AbonTable.FieldByName("Code").AsInteger;
    ParamByName("inCounterCode").Value:= AbonTable.FieldByName("CurCounterCode").AsInteger;
    ParamByName("inInputDate").Value    := edPlategDate.DateTime;
    dbCommand.Execute;

    cxTextEdit1.EditValue := ParamByName("outKwt").Value;
 end;
и зачем она? неужели намного проще чем вот эта запись?
после изменения запроса параметры неопределены, т.е. нужно обязательно присвоение типизированного значения (asInteger/asDateTime а не value), впрочем, может это кроме как на дату и не влияет... просто я привык так. читаешь справку, что рекомендуют и делаеш именно так.

> что надо делать отдельный ADOCommand для каждой ХП чтоли?
а ты их что экономишь?...
положи на форму 1 ADOCommand, скомпили, посмотри размер, теперь положи 128 ADOCommand-ов скомпили, посмотри размер. на много изменилось?

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


 
sniknik ©   (2008-01-18 17:23) [5]

кстати если решишь положить запрос в ADOCommand в десигне, то лучше выставь тип команды cmdStoredProc, и выбери нужную процедуру. параметры оно подцепит само, нужно лиш подключение к базе на тот момент.


 
DeadMeat ©   (2008-01-18 20:55) [6]

Да что я седня туплю... Толи не нажал.. Толи не ушло.. Блин.. Стока писал.
Попробую еще раз.
Так или иначе... спасибо за разъяснения. По поводу "экономии на ADOCommand".. дело не в размерах... а казалось, что это.... как бы... ну не красиво чтоли... когда можно обойтись одним. Но как выяснилось... не желательно. При таком подходе... особый смысл в моей ExecuteCommand отпадает. А полезна она была чисто для удобства... не надо перечислять названия параметров... а просто передать уже их значения.. Я полагал, что передавая через variant, "структура данных" в переменной не меняется.
Насчет cmdStoredProc знаю... так в начале и делал.... кучу ADOCommand... Но как уже описал выше... полагал что не стоит оно того. Оказалось - стоит.

В общем еще раз спасибо.. выручаете как обычно.
Единственное чего я так и не догнал, так почему же произошло "округление"? Интерес еще тот факт... что как видно из кода, даты там две... Обе абсолютно одинаковые компоненты... Ведут себя тоже совершенно одинаково.. надеюсь по крайней мере.. Так вот дата одного из них не "округлялась" и пришла с временем 00:00:00.
Просто я давно с датами работаю... так же давно их передаю через параметры этим же способом.. Работал и со временем тоже (т.е. были задачи, где надо время тоже учитывать). Ни разу эта проблема не вылезала.. А тут......


 
sniknik ©   (2008-01-18 23:57) [7]

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

> что как видно из кода, даты там две...
где? одну только вижу - inInputDate.

> Ни разу эта проблема не вылезала.. А тут......
выполни
DateTimePicker1.DateTime:= Now();
ShowMessage(DateTimeToStr(DateTimePicker1.Date));
а перед этим скажи чисто по логике, что покажет?...

и даже знаю почему. зайди в GetDate компонента и посмотри код.

а твои одинаковые компоненты... ну если они по такому же принципу работают, смотри у них, что во времени стоит.


 
Palladin ©   (2008-01-19 00:12) [8]

млин, мне это напоминает человека живущего перед анусом...
а сникнику жестокий респект за попытку влезть в этот анус вытащить человека на чистый воздух... самое интересное ADO то здесь вообще ни причем...

начем разбор полетов


>  Работаю с Turbo Delphi Pro + DevExpress + ADO + MSSQL 2005.

ну зашибись, но DevExpress уже настораживает

[2] пост, полный бред, абсолютно, бо товарищ просто абсолютно не понимает что же такое DateEdit в DevExpress, казалось бы почему? а потому что он нихера [1] не прочитал, ну что ж, респект и уважение, бо если ты собираешься передавать значение параметра даты ты обязан использовать trunc(value) при присвоении параметра, соответственно кстати к значениям в базе, например в MS Jet это сканает, бо у него есть специалтельный формат даты без учета времени, а вот для MSSQL не сканает, нужно придумывать правильный механизм обработки даты из DateEdit

уточнения по поводу DevExpress, ну нету у них PropertyEditClasses для Time и для Date по отдельности, по крайней мере это справедливо для четверки


 
DeadMeat   (2008-01-19 00:35) [9]


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

Ну так и есть.. Ведь вызывается не одна и та же ХП, а разные (и не только ХП). Вот и пересоздается все. У меня же она была одна на всех. Сейчас я уже понял, что лучше делать как раньше хотел.


> где? одну только вижу - inInputDate.

Прошу простить великодушно... Второй пикер стоял на вызов другой процедуры.. Аврал на работе.. Серьезные кадровые перестановки. С ручника еще не снялся.


> выполни
> DateTimePicker1.DateTime:= Now();
> ShowMessage(DateTimeToStr(DateTimePicker1.Date));
> а перед этим скажи чисто по логике, что покажет?...

Чисто по логике? Покажет текущие дату и время. Нет? Проверять щас негде. А покажет, потому что там тип общий вроде.. TDateTime. И функция (щас 3 раза переписал это слово) вроде как при форматировании не откидывает время от даты. Я не прав?


> ну зашибись, но DevExpress уже настораживает

Эмм... А почему?


> уточнения по поводу DevExpress, ну нету у них PropertyEditClasses
> для Time и для Date по отдельности, по крайней мере это
> справедливо для четверки

Не совсем понял эту часть... Четверка это которая? 4.хх ? У меня щас 6.31

По поводу вопроса...
Ну предположим, что я идиёт. Предположим, что передавать надо целиком дату+время (т.е. как есть). Почему при передаче через variant, используя только что созданные параметры (автоматом), дата приходит "округленной"? Все-же раньше такое не возникало. А с течением времени ничего я в этой части в разных проектах не менял. Передавал так же и целиком со временем.
Сейчас уже ясно, что надо тип выставлять... Но ведь не делал же.


 
sniknik ©   (2008-01-19 01:48) [10]

> в MS Jet это сканает
даже передача числом "сканает" так как в нем точка отсчета дат совпадает с дельфеской... вот такие они загадочные в мелкософте, пишут в одном месте но по разному почемуто (почему так догадки есть... но больно они "мутные").
а вот со временем не все так просто, "чистые" типы, названия, есть но они уже давно синонимы с основным... время "откинет" разве что для парадокса, дбейса, при записи, у которых есть такие типы полей.

> Покажет текущие дату и время. Нет?
какойто ты не логичный, запрос от компонента  идет даты (.Date), а говоришь покажет дату и время... посмотрел наверное. для даты и времени есть .DateTime, а вот запрос по части, должны (логично) часть и выдавать... на этом многие "ловятся".

> Предположим, что передавать надо целиком дату+время (т.е. как есть).
не как есть, а как надо (! разница), если нужно со временем значит со временем, нужно без, значит обнулить время но передавать все одно общим типом дататайм, т.к. в mssql другого нет. (есть короткая/длинная дата, но и там и там со временем)

> Все-же раньше такое не возникало.
это логический глюк (самый хреновый)... как вариант, предположу, что "раньше" ты проверял это утром...
а еще не обращали внимания, ведь работает же! (скомпилилось, и ошибок не выдало)


 
sniknik ©   (2008-01-19 01:54) [11]

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


 
DeadMeat ©   (2008-01-19 12:00) [12]

Мда... Я не просто скомпилил и бросил. Я реально проверял. К примеру у меня была выборка по периоду. Правда тогда я не ХП вызывал, а просто селект типа:

select f1, f2....
from t1
where f1 between :date1 and :date2

Результат был всегда верный. Может есть разница между использованием такого подхода (через variant) в селектах и в вызове ХП?


> какойто ты не логичный, запрос от компонента  идет даты
> (.Date), а говоришь покажет дату и время... посмотрел наверное.
>  для даты и времени есть .DateTime, а вот запрос по части,
>  должны (логично) часть и выдавать... на этом многие "ловятся".

Ну я честно сказал, что проверять мне негде. А почему ответил так, потому что (как я раньше писал) мне известно, что это за тип такой.. что время отдельно от него не идет. Проблема изначально была в двух вещах, которые мне показались странными:
1. Почему было приписано время 23:59:59 (а не 00:00:00)
2. И почему в ХП пришла "округленная" дата. Т.е. когда я передал: 01.02.2007 23:59:59... профайлер показал, что пришло 02.02.2007 00:00:00.
Вот эти два пункта с самого начала мне показались странными. Ну если с первым еще можно смириться (прикол DevExpress), то второй для меня не ясен. Ведь так или иначе передалась дата целиком, хоть и через variant.


 
Anatoly Podgoretsky ©   (2008-01-19 23:14) [13]

> DeadMeat  (19.01.2008 12:00:12)  [12]

Я бы не рискнул передавать даты через варианты, граблей не напасешься.

Насчет 01.02.2007 23:59:59... вот в этих точках и во взаимодействие всех частей и главное.
Возможно у тебя 01.02.2007 23:59:59,997


 
DeadMeat ©   (2008-01-20 12:15) [14]


> Я бы не рискнул передавать даты через варианты, граблей
> не напасешься.

А так хотелось.....


> Насчет 01.02.2007 23:59:59... вот в этих точках
> и во взаимодействие всех частей и главное.Возможно у тебя
> 01.02.2007 23:59:59,997

Видимо так и выходит.... По логике, раз там 23:59:59, то вероятно и миллисекунды тоже 999 (или еще какие). Все же не понятно, почему происходит "округление". А если мне по задаче надо и миллисекунды использовать?


 
sniknik ©   (2008-01-20 12:45) [15]

> Все же не понятно, почему происходит "округление".
включи трассировку модулей, протрассируй присвоение,  да посмотри...

> А если мне по задаче надо и миллисекунды использовать?
тогда обломись...
датавремя представленное в варианте не имеет такой точности, а обойти вариант ты не сможешь, параметр тоже он... пусть он там уже получил правильный тип но точность то никуда не делась...
(нужен тип датавремямилисекунды... :)

в mssql кстати тоже не все гладко с миллисекундами, на последние разряды тоже точности не хватает, значения дискретные получаются (типа :001 :003 :005, ну вроде того. проверь)
в дельфи наверняка аналогично.

поэтому если действительно миллисекунды нужны (то значит и точность необходима), то лучше их отдельно держать.
или, если вместе, надо мудрить с передачей в запрос, например строкой (плохой вариант), или раздельной передачей, передавать отдельно от общего датывремени, и в запросе "приплюсовывать"... или еще чего придумать на что фантазии хватит.


 
Anatoly Podgoretsky ©   (2008-01-20 14:15) [16]

> sniknik  (20.01.2008 12:45:15)  [15]

В MS SQL датавремя представлено с точностью только 3 мм (0, 3, 7...) все значения округляются к этой точности и тут если нет понимания, то получаются проблемы с BETWEEN


 
DeadMeat   (2008-01-20 16:22) [17]

Ну теперь та все понятно...
Благодарю всех за помощь.
Век живи - век учись.



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

Форум: "Базы";
Текущий архив: 2008.06.22;
Скачать: [xml.tar.bz2];

Наверх





Память: 0.53 MB
Время: 0.041 c
1-1195029359
tytus
2007-11-14 11:35
2008.06.22
TSimpeObjectBroker - как переключить клиента на другой сервер?


10-1118062128
som
2005-06-06 16:48
2008.06.22
Ошибка при заполнении таблицы данными (Word)


1-1195378114
MikeLevinN
2007-11-18 12:28
2008.06.22
TListView


2-1211838168
dellow
2008-05-27 01:42
2008.06.22
Проблема с типом данных.


2-1211782721
Xmen
2008-05-26 10:18
2008.06.22
Как можно передать данные из текушего приложения другую и нажать





Afrikaans Albanian Arabic Armenian Azerbaijani Basque Belarusian Bulgarian Catalan Chinese (Simplified) Chinese (Traditional) Croatian Czech Danish Dutch English Estonian Filipino Finnish French
Galician Georgian German Greek Haitian Creole Hebrew Hindi Hungarian Icelandic Indonesian Irish Italian Japanese Korean Latvian Lithuanian Macedonian Malay Maltese Norwegian
Persian Polish Portuguese Romanian Russian Serbian Slovak Slovenian Spanish Swahili Swedish Thai Turkish Ukrainian Urdu Vietnamese Welsh Yiddish Bengali Bosnian
Cebuano Esperanto Gujarati Hausa Hmong Igbo Javanese Kannada Khmer Lao Latin Maori Marathi Mongolian Nepali Punjabi Somali Tamil Telugu Yoruba
Zulu
Английский Французский Немецкий Итальянский Португальский Русский Испанский