Как перенести datetime на datetime2 с новым собственным клиентом SQL Server

В настоящее время мы переносим нашу базу данных из datetimeв datetime2 включая собственный клиент SQL Server v11 (SQL Server 2012). Обновление базы данных было легко сделано, но проблемы возникают вместе с новым SQL Server Native Client 11, который мы хотим использовать.

В целом у нас есть потребители OLE DB с аксессорами «COLUMN_ENTRY *» для наших операций CRUD. Для datetime2 столбцы члены имеют тип DBTIMESTAMP, С SQLNCLI поставщик фракция часть DBTIMESTAMP был молча усечен до поддерживаемого значения. С SQLNCLI11 вставка со слишком точной дробью приводит к этой ошибке:

DB_E_ERRORSOCCURRED Multiple-step OLE DB operation generated errors. Check each OLE DB status value, if available. No work was done.

В соответствии с эта ссылка, эта ошибка возвращается, если в поле вставлено слишком много данных. Исходя из этого, я предположил, что дробная часть члена DBDATETIME слишком точна для вставки. В соответствии с эта ссылка, новые версии Native Client (10 и 11) не усекаются, но выдают ошибку. Возьмите этот упрощенный пример того, чего мы хотим достичь:

class CMyTableStruct
{
public:
CMyTableStruct();
LONG m_lID;
DBTIMESTAMP m_dtLogTime;
};
class CMyTableStruct_InsertAccessor : public CMyTableStruct
{
public:
BEGIN_PARAM_MAP(CMyTableStruct_InsertAccessor)
COLUMN_ENTRY(1,  m_dtLogTime)
END_PARAM_MAP()
};

В какой-то части кода я инициализирую метку времени на 2015-08-10 07: 47: 49.986149999, и вставка не выполняется. Если я сбрасываю дробь на 0, вставка работает; любое значение, кроме 0, терпит неудачу. Я попытался предоставить точность даты и времени, используя COLUMN_ENTRY_PS с различными значениями, но вставки всегда не удалось.

Как мы можем заставить собственный клиент просто принять значение и урезать его? Совершенно очевидно, что мы не можем усечь все значения вручную до поддерживаемой точности БД. Я не смог найти надлежащей документации о том, как использовать datetime2 с новым Native Client. Мы пропускаем какие-либо преобразования или настройки для корректной обработки datetime2?

Это тестовая настройка:

  • Windows 7 64bit
  • Собственный клиент SQL Server 11 (SQLNCLI11)
  • SQL Server 2012
  • DBPROP_INIT_LCID = 2055
  • DBPROP_INIT_PROMPT = 4
  • DBPROP_INIT_DATASOURCE = локальный
  • DBPROP_AUTH_INTEGRATED = ССПИ

С SQLNCLI провайдер тот же код работает.

[РЕДАКТИРОВАТЬ # 1]: я сбросил еще немного информации об ошибках, используя AtlTraceErrorRecords и это подтвердило ту же ошибку, что и в связанном отчете Microsoft Connect:

Row #: 0 Source: "Microsoft SQL Server Native Client 11.0" Description: "The fractional part of the provided time value overflows the scale of the corresponding SQL Server parameter or column. Increase bScale in DBPARAMBINDINFO or column scale to correct this error." Help File: "(null)" Help Context: 0 GUID: {0C733A63-2A1C-11CE-ADE5-00AA0044773D}

[РЕДАКТИРОВАТЬ # 2]: Из моих дальнейших исследований похоже, что это определенное и принятое поведение нового Native Client. Увидеть Более строгая проверка параметров SQL_C_TYPE _TIMESTAMP и DBTYPE_DBTIMESTAMP для справки. Но Microsoft не может принять это изменение всерьез без какой-либо документации о том, как правильно использовать datetime2. Действительно ли они требуют, чтобы сами разработчики округлили DBTIMESTAMP перед вставкой их в базу данных? В некоторых случаях округление даже не работает из-за некоторых ошибок точности с плавающей запятой. Возьмите пример временной метки сверху, и вы увидите типичную ошибку точности в .9999. Как можно заставить это странное поведение работать? С этими сообщениями об ошибках вы даже не можете сохранить текущую метку времени в базе данных без использования функции SQL для now() потому что вы обычно работаете в этих переполнениях.

3

Решение

Я сделал несколько тестов и полностью переписал свой ответ.

Я использую SQL Server 2008 с Native Client 10. Он уже поддерживает datetime2(7)так что мои тесты применимы.

Дата и время

У меня есть хранимая процедура, которая имеет табличный параметр. Один из столбцов таблицы параметров имеет datetime тип. Я не использовал ненулевые доли секунды раньше, но попробовал сейчас. Мне потребовалось некоторое время, чтобы понять, что нужно.

Чтобы использовать ненулевое значение в DBTIMESTAMP.fraction поле мне нужно было настроить как описание столбца, так и описание параметра: установить DBCOLUMNDESC.bScale до 3 и DBBINDING.bScale до 3. Оба bPrecision был оставлен в 0. Это Документ MSDN помог мне понять, что я должен установить DBCOLUMNDESC.bScale также.

Поставщик OLE DB для собственного клиента SQL Server проверяет DBCOLUMDESC
bScale член для определения точности долей секунды.

однажды Scale установлен на 3, я мог бы установить значение DBTIMESTAMP.fraction в 555000000 и он был успешно вставлен в базу данных как .557сервер округляет это значение до 1/3 миллисекунды (точность datetime тип). Но, когда я пытался установить значение DBTIMESTAMP.fraction в 552100000Я получил ту же ошибку, что и вы. Таким образом, сервер ожидает, что программисты сами округляют значения.

Один простой способ обрезать дроби будет примерно так:

DBTIMESTAMP dt;
// set to any value from 0 to 999,999,999 (billionth of a second)
dt.fraction = 555123456;

// truncate fractions to milliseconds before inserting into the database
dt.fraction /= 1000000;
dt.fraction *= 1000000;

datetime2 (7)

Я изменил тип столбца в табличном параметре на datetime2(7) и сделал еще несколько тестов.

Я поставил Scale до 7 и может успешно вставить в базу данных DBTIMESTAMP.fraction со значением 555123400, но когда я попытался вставить значение 555123478 Я получил ту же ошибку. Таким образом, для datetime2(7) Сервер также ожидает, что программисты сами округляют значения.

// truncate fractions to 100 nanoseconds precision
dt.fraction /= 100;
dt.fraction *= 100;

Должно быть достаточно.

2

Другие решения

При использовании C # или VB с библиотекой OleDb установите значение OleDbParameter.Scale, чтобы избежать этого сообщения об ошибке.

Протестировано с Provider = SQLNCLI11.

0

По вопросам рекламы [email protected]