Добро пожаловать в форум, Guest  >>   Войти | Регистрация | Поиск | Правила | В избранное | Подписаться
Все форумы / Microsoft SQL Server Новый топик    Ответить
 Можно в ADO при использовании MSOLEDBSQL явно указывать тип SQLSever в параметрах запроса?  [new]
Dimitry Timokhov
Member

Откуда: Москва
Сообщений: 71
Приветствую!

1. По совету коллег разбираюсь с провайдером MSOLEDBSQL (на замену SQLOLEDB). В тестовых примерах он реально быстрее на мелких запросах. Но в рабочей базе есть проблемы с датами, которые хочу решить (залатать) на переходный период.

2. Что делаю:
  • Создаю ADO.Parameter.
  • Задаю prm.Type = adDBDate.
  • В при выполнении запроса ADO направляет серверу такой запрос:
exec sp_executesql N'select count(*) as [Count] from [Table] where [Datе] < @P1',N'@P1 date','2019-08-26'


3. Вопрос: есть ли возможность сказать ADO (или провайдеру MSOLEDBSQL), чтобы вместо типа date она использовала тип datetime (или smalldatetime)?

Причем, в ходе работы программы в обновленных местах нужно date, в старых местах datetime. Т.е. прибить гвоздями один раз на всё время работы программы нельзя - надо иметь возможность это настраивать.

Спасибо!
12 дек 19, 23:48    [22039254]     Ответить | Цитировать Сообщить модератору
 Re: Можно в ADO при использовании MSOLEDBSQL явно указывать тип SQLSever в параметрах запроса?  [new]
a_voronin
Member

Откуда: Москва
Сообщений: 4404
Dimitry Timokhov,

Непонятная проблема. Нужен datetime, используйте datetime:

exec sp_executesql N'select count(*) as [Count] from [Table] where [Datе] < @P1',N'@P1 datetime','2019-08-26'

exec sp_executesql N'select count(*) as [Count] from [Table] where [Datе] < cast(@P1 as datetime)',N'@P1 date','2019-08-26'
13 дек 19, 08:08    [22039323]     Ответить | Цитировать Сообщить модератору
 Re: Можно в ADO при использовании MSOLEDBSQL явно указывать тип SQLSever в параметрах запроса?  [new]
alexeyvg
Member

Откуда: Moscow
Сообщений: 30830
a_voronin
Непонятная проблема. Нужен datetime, используйте datetime:
Угу, в данном случае нужно написать prm.Type = adDBTimeStamp вместо prm.Type = adDBDate.

Тем более, если надо:
Dimitry Timokhov
Причем, в ходе работы программы в обновленных местах нужно date, в старых местах datetime. Т.е. прибить гвоздями один раз на всё время работы программы нельзя - надо иметь возможность это настраивать
Как иначе серверу сказать, где что юзать, как не указанием нужных типов в соответствующем месте?

Не может же быть в MSOLEDBSQL настройки "Тип данных для старых мест".
13 дек 19, 09:00    [22039341]     Ответить | Цитировать Сообщить модератору
 Re: Можно в ADO при использовании MSOLEDBSQL явно указывать тип SQLSever в параметрах запроса?  [new]
Владислав Колосов
Member

Откуда:
Сообщений: 7407
Dimitry Timokhov,

на время переходного периода должны использовать оба типа запроса - старого образца и нового. Придумайте селектор.
13 дек 19, 11:11    [22039475]     Ответить | Цитировать Сообщить модератору
 Re: Можно в ADO при использовании MSOLEDBSQL явно указывать тип SQLSever в параметрах запроса?  [new]
Владислав Колосов
Member

Откуда:
Сообщений: 7407
Dimitry Timokhov,

... и поищите книги о рефакторинге SQL.
13 дек 19, 11:11    [22039477]     Ответить | Цитировать Сообщить модератору
 Re: Можно в ADO при использовании MSOLEDBSQL явно указывать тип SQLSever в параметрах запроса?  [new]
Dimitry Timokhov
Member

Откуда: Москва
Сообщений: 71
a_voronin
Dimitry Timokhov,

Непонятная проблема. Нужен datetime, используйте datetime:

exec sp_executesql N'select count(*) as [Count] from [Table] where [Datе] < @P1',N'@P1 datetime','2019-08-26'


exec sp_executesql N'select count(*) as [Count] from [Table] where [Datе] < cast(@P1 as datetime)',N'@P1 date','2019-08-26'


Почему же непонятная?

1. Сразу насчет каста в запросе. Это понятно, что можно. Забыл сказать, что менять запрос не хотелось бы. Мне было бы достаточно нужный мне тип datetime рядом с @P1 во втором параметре sp_executesql.

2. Дабы пояснить лучше ситуацию, приведу пример.
Пример на дельфи, но он либы от дельфи не использует - все на позднем связывании прямо через OLE. Примерно это будет написано в любом языке.

Суть примера: для провайдеров SQLOLEDB и MSOLEDBSQL, для двух методов добавления параметров в ADO.Command, для четырех типов дат делает тривиальный запрос с параметром типа дата.

NB Можно выполнять на любой БД - ничего в БД не меняет.

var
   ProviderI, DatePrmTypeI, PrmMethodI: Integer;
   Provider: String;
   DateType: Integer;
   DateTypeAsStr: String;
   Cnn, Prm, Cmd: OleVariant;
begin
   for ProviderI := 1 to 2 do
   begin
      case ProviderI of
         1: Provider := 'SQLOLEDB';
         2: Provider := 'MSOLEDBSQL';
      end;

      Cnn := CreateOleObject('ADODB.Connection');
      Cnn.Open('Provider='+Provider+';Server=<server>;Database=<datebase>;Trusted_Connection=Yes;Application name=test1');
      try
         for PrmMethodI := 1 to 2 do
         begin
            for DatePrmTypeI := 1 to 4 do
            begin
               case DatePrmTypeI of
                  1: begin DateType := $00000007{adDate       }; DateTypeAsStr := 'adDate'        end;
                  2: begin DateType := $00000085{adDBDate     }; DateTypeAsStr := 'adDBDate'      end;
                  3: begin DateType := $00000086{adDBTime     }; DateTypeAsStr := 'adDBTime'      end;
                  4: begin DateType := $00000087{adDBTimeStamp}; DateTypeAsStr := 'adDBTimeStamp' end;
               end;

               Prm := CreateOleObject('ADODB.Parameter');
               Prm.Direction := $00000001{adParamInput};
               Prm.Type := DateType;
               Prm.Value := Variant(EncodeDate(2019, 10, 12));

               Cmd := CreateOleObject('ADODB.Command');
               Cmd.ActiveConnection := Cnn;
               Cmd.CommandText := '/*'+Provider+'.'+IntToStr(PrmMethodI)+'.'+DateTypeAsStr+'*/ select ?';
               case PrmMethodI of
                  1:
                  begin
                     Cmd.Execute(Parameters := Variants.VarArrayOf([Prm]), Options := $00000080{adExecuteNoRecords}+$00000001{adCmdText});
                  end;
                  2:
                  begin
                     Cmd.Parameters.Append(Prm);
                     Cmd.Execute(Options := $00000080{adExecuteNoRecords}+$00000001{adCmdText});
                  end;
               end;
            end;
         end;
      finally
         Cnn.Close;
      end;
   end;
end;


Посмотрите, какая интересная выдача получается (к моему вопросу не относится, просто интересный и для меня необъяснимый факт):

exec sp_executesql N'/*SQLOLEDB.1.adDate*/ select @P1',N'@P1 datetime','2019-10-12 00:00:00'
exec sp_executesql N'/*SQLOLEDB.1.adDBDate*/ select @P1',N'@P1 datetime','2019-10-12 00:00:00'
exec sp_executesql N'/*SQLOLEDB.1.adDBTime*/ select @P1',N'@P1 datetime','2019-10-12 00:00:00'
exec sp_executesql N'/*SQLOLEDB.1.adDBTimeStamp*/ select @P1',N'@P1 datetime','2019-10-12 00:00:00'

exec sp_executesql N'/*SQLOLEDB.2.adDate*/ select @P1',N'@P1 datetime','2019-10-12 00:00:00'
exec sp_executesql N'/*SQLOLEDB.2.adDBDate*/ select @P1',N'@P1 datetime','2019-10-12 00:00:00'
exec sp_executesql N'/*SQLOLEDB.2.adDBTime*/ select @P1',N'@P1 datetime','2019-10-12 00:00:00'
exec sp_executesql N'/*SQLOLEDB.2.adDBTimeStamp*/ select @P1',N'@P1 datetime','2019-10-12 00:00:00'

exec sp_executesql N'/*MSOLEDBSQL.1.adDate*/ select @P1',N'@P1 date','2019-10-12'
exec sp_executesql N'/*MSOLEDBSQL.1.adDBDate*/ select @P1',N'@P1 date','2019-10-12'
exec sp_executesql N'/*MSOLEDBSQL.1.adDBTime*/ select @P1',N'@P1 date','2019-10-12'
exec sp_executesql N'/*MSOLEDBSQL.1.adDBTimeStamp*/ select @P1',N'@P1 date','2019-10-12'

exec sp_executesql N'/*MSOLEDBSQL.2.adDate*/ select @P1',N'@P1 datetime2(0)','2019-10-12 00:00:00'
exec sp_executesql N'/*MSOLEDBSQL.2.adDBDate*/ select @P1',N'@P1 date','2019-10-12'
exec sp_executesql N'/*MSOLEDBSQL.2.adDBTime*/ select @P1',N'@P1 time(0)','00:00:00'
exec sp_executesql N'/*MSOLEDBSQL.2.adDBTimeStamp*/ select @P1',N'@P1 datetime2(0)','2019-10-12 00:00:00'


Т.е. SQLOLEDB для любого способа добавления параметра (метод 1: сразу передавать параметры в ADO.Command.Execute; метод 2: сначала параметр добавить в ADO.Command.Parameters, а в ADO.Command.Execute ничего не передавать) параметр имеет тип datetime.
Для MSOLEDBSQL параметры для метода 1 и 2 различаются!!! Интересный факт. Что бы это значило?

Вернусь к исходному вопросу. Хотелось бы, чтобы я мог настраивать, чтобы MSOLEDBSQL также как SQLOLEDB использовал тип datetime рядом с @P1 во втором параметре sp_executesql. Можно управлять тем, какой тип параметра будет использовать ADO?



PS Для справки. Запрос select @@version дает: Microsoft SQL Server 2012 - 11.0.2100.60 (X64) Feb 10 2012 19:39:15 Copyright (c) Microsoft Corporation Developer Edition (64-bit) on Windows NT 6.2 <X64> (Build 9200: )

Сообщение было отредактировано: 13 дек 19, 15:28
13 дек 19, 15:27    [22039823]     Ответить | Цитировать Сообщить модератору
 Re: Можно в ADO при использовании MSOLEDBSQL явно указывать тип SQLSever в параметрах запроса?  [new]
Dimitry Timokhov
Member

Откуда: Москва
Сообщений: 71
Dimitry Timokhov,

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

Весь секрет в добавке в ADODB.Connection.ConnectionString опции DataTypeCompatibility=80. Тогда второй параметр sp_executesql для типа ADODB.adDate будет равен datetime.

PS Вся проблема в том, что наша БД, исходно реализована на SQL2000. А там не было типа date. Почему-то (не знаю, почему) для дат (а нам нужны только даты, без времени) был использован int. Тип int совместим в datetime и smalldatetime, но не совместим в date (который появился позднее). Понятно, что нужно переходить на date. Но это не сразу, нужен переходный период.
14 дек 19, 04:04    [22040336]     Ответить | Цитировать Сообщить модератору
Все форумы / Microsoft SQL Server Ответить