В настоящее время мы переносим нашу базу данных из 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?
Это тестовая настройка:
С SQLNCLI
провайдер тот же код работает.
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}
now()
потому что вы обычно работаете в этих переполнениях.
Я сделал несколько тестов и полностью переписал свой ответ.
Я использую 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;
Должно быть достаточно.
При использовании C # или VB с библиотекой OleDb установите значение OleDbParameter.Scale, чтобы избежать этого сообщения об ошибке.
Протестировано с Provider = SQLNCLI11.