Какой тип данных следует связать в качестве параметра запроса для использования со столбцом NUMBER (15) в Oracle ODBC? - PullRequest
4 голосов
/ 15 июля 2010

Меня только что укусила проблема, описанная в SO вопросе Привязка int64 (SQL_BIGINT), так как параметр запроса вызывает ошибку при выполнении в Oracle 10g ODBC .

Я портирую C /Приложение C ++, использующее ODBC 2 из SQL Server в Oracle.Для числовых полей, превышающих NUMBER (9), он использует тип данных __int64, который связан с запросами как SQL_C_SBIGINT.Очевидно, такое связывание не поддерживается Oracle ODBC.Теперь я должен преобразовать приложение в другой метод.Поскольку у меня не так много времени - это неожиданная проблема - я бы предпочел использовать проверенное решение, а не метод проб и ошибок.

Какой тип данных следует использовать для привязки, например, NUMBER (15) в Oracle? Есть ли документированное рекомендуемое решение?Что вы используете?Любые предложения?

Меня особенно интересуют решения, которые не требуют каких-либо дополнительных преобразований.Я могу легко предоставлять и потреблять числа в форме __int64 или char * (обычная неэкспоненциальная форма без разделителя тысяч или десятичной точки).Любой другой формат требует дополнительного преобразования с моей стороны.


То, что я пробовал до сих пор:

SQL_C_CHAR

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

И я не понимаю, почему я должен использовать явное приведение (например, TO_NUMERIC) в команде SQL INSERT или UPDATE.Все работает нормально, когда я связываю параметр с SQL_C_CHAR как тип C и SQL_NUMERIC (с правильной точностью и масштабированием) как тип SQL.Я не смог воспроизвести эффект повреждения данных.

SQL_NUMERIC_STRUCT

Я заметил, что SQL_NUMERIC_STRUCT добавлен в ODBC 3.0, и решил попробовать.Я разочарован.

В моей ситуации этого достаточно, поскольку приложение на самом деле не использует дробные числа.Но как общее решение ... Просто я не понимаю.Я имею в виду, я наконец понял, как это должно быть использовано.Чего я не понимаю: , почему кто-то вводит новую структуру такого рода и затем заставляет ее работать таким образом .

SQL_NUMERIC_STRUCT имеет все необходимые поля для представления любого NUMERIC (или NUMBERили DECIMAL) значение с его точностью и масштабом.Только они не используются.

При чтении ODBC устанавливает точность числа (в зависимости от точности столбца; за исключением того, что Oracle возвращает большую точность, например, 20 для NUMBER (15)).Но если ваш столбец имеет дробную часть (масштаб> 0), он по умолчанию усекается.Чтобы прочитать число с правильным масштабом, вам нужно установить точность и масштабировать себя с помощью вызова SQLSetDescField перед извлечением данных.

При записи Oracle, к счастью, учитывает масштаб, содержащийся в SQL_NUMERIC_STRUCT.Но спецификация ODBC не требует этого, и MS SQL Server игнорирует это значение.Итак, снова вернемся к SQLSetDescField.

См. HOWTO: получение числовых данных с помощью SQL_NUMERIC_STRUCT и INF: как использовать тип данных SQL_C_NUMERIC с числовыми данными для получения дополнительной информации.

Почему ODBC не полностью использует свой собственный SQL_NUMERIC_STRUCT?Я не знаю.Похоже, что это работает, но я думаю, что это слишком много работы.


Я думаю, я буду использовать SQL_C_CHAR.

1 Ответ

2 голосов
/ 15 июля 2010

Мое личное предпочтение - сделать символьные строки для связывания переменных (VARCHAR2) и позволить Oracle выполнять преобразование из символа в собственный формат внутреннего хранилища.Достаточно легко (в C) получить значения данных, представленные в виде строк с нулевым символом в конце, в приемлемом формате.

Итак, вместо того, чтобы писать SQL следующим образом:

SET MY_NUMBER_COL = :b1
  , MY_DATE_COL = :b2

Я пишу SQL следующим образом:

SET MY_NUMBER_COL = TO_NUMBER( :b1 )
  , MY_DATE_COL   = TO_DATE( :b2 , 'YYYY-MM-DD HH24:MI:SS')

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

У этого подхода есть несколько преимуществ.

Одно из них заключается в том, что обходятся проблемы и ошибки, возникающие при связывании других типов данных.

Другое преимущество заключается в том, что связываются значениялегче расшифровать трассировку события Oracle 10046.

Кроме того, EXPLAIN PLAN (я полагаю) ожидает, что все переменные связывания будут VARCHAR2, поэтому это означает, что объясняемый оператор немного отличается от фактического выполняемого оператора(из-за неявных преобразований данных, когда типы данных аргументов связывания в фактическом операторе не являются VARCHAR2.)

И (менее важно), когда я тестирую оператор в TOAD, проще бытьвозможность вводить строки в поля ввода, и не нужно гадить с изменением типа данных в раскрывающемся списке.

Я также позволил bФункции TO_NUMBER и TO_DATE проверяют данные.(По крайней мере, в более ранних версиях Oracle я сталкивался с проблемами с привязкой значения DATE напрямую, и он обошел (по крайней мере, некоторые из) проверку достоверности и позволил хранить недопустимые значения даты в базе данных.

Это просто личное предпочтение, основанное на прошлом опыте. Я использую этот же подход с Perl DBD.

Интересно, что Том Кайт (asktom.oracle.com) может сказать по этой теме?

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