#vb.net #oracle #datetime
#vb.net #Oracle #дата и время
Вопрос:
Помогите, есть идеи??
Я использую адаптер OLEDB (Oracle OLEDB) с Oracle 10.2.0.3.0. Мой код генерирует SQL для запроса, затем, когда я выполняю его в OleDbDataReader, значение HasRows равно False . Однако, если я выведу содержимое строки запроса, скопирую и вставлю в SQL (войдя в систему как тот же пользователь с того же клиентского компьютера), он вернет 993 строки. Что дает??
Вот фрагмент моего кода:
Dim DB As New OleDb.OleDbConnection(String.Format("{0};Password={1}", ConnectionString, DBPassword))
Dim flowQuerySQL As String
'... code to generate query
Debug.Print(flowQuerySQL)
Dim flowQueryCMD As New OleDb.OleDbCommand(flowQuerySQL, DB)
Dim flowQuery As OleDb.OleDbDataReader = flowQueryCMD.ExecuteReader()
While flowQuery.HasRows
'...handle rows
End While
Инструкция debug.print показывает:
SELECT CLASS_ID, OBJECT_ID FROM TDM_SF_PROCESS WHERE CLASS_ID=853 AND TDM_END_TIME >= '01-Jan-2009' AND TDM_END_TIME < '31-May-2009' AND TDM_STATUS <> 1 AND TDM_STATUS <> 2
Комментарии:
1. Есть только один результат? Который вы потребляете, и теперь HasRows является false?
2. Обратите внимание, что следующим оператором после выполнения команды является
While flowQuery.HasRows
. Тем не менее, я просто попытался удалить даты из запроса, и теперьHasRows
естьTrue
. Почему это так? Есть ли что-то в OleDb, что требует даты в формате, отличном от того, что хочет Oracle? Я пробовал даты и время, но это дало мне ORA-01861.
Ответ №1:
Я только недавно начал работать VB.NET против Оракула, а даты темпераментны.
Этот подход работал для меня до сих пор:
SELECT CLASS_ID, OBJECT_ID
FROM TDM_SF_PROCESS
WHERE CLASS_ID=853
AND TDM_END_TIME >= TO_DATE('01-Jan-2009', 'DD-Mon-YYYY')
AND TDM_END_TIME < TO_DATE('31-May-2009', 'DD-Mon-YYYY')
AND TDM_STATUS <> 1
AND TDM_STATUS <> 2
Это не сработало бы, пока я не использовал функцию «TO_DATE». Надеюсь, это сработает и для вас.
Я специалист по MS-SQL, поэтому мне пока не удалось выяснить, «почему» почему это работает. Просветление, кто-нибудь?
Комментарии:
1. 1 да, после просмотра некоторых моих старых кодов я тоже использую TO_DATE. По какой-то причине строки не анализируются правильно, если они не в системном формате Oracle. На самом деле я использую это: to_date(‘24.10.2011′,’мм / дд / гггг’) и даже использую его в качестве ключа автозапуска.
2. Черт, я думал, что это пройдет! Вот SQL, который он выполняет:
SELECT CLASS_ID, OBJECT_ID, TDM_END_TIME FROM TDM_SF_PROCESS WHERE CLASS_ID=862 AND TDM_END_TIME >= TO_DATE('1-Jan-2009', 'DD-Mon-YYYY') AND TDM_END_TIME < TO_DATE('31-May-2009', 'DD-Mon-YYYY') AND TDM_STATUS <> 1 AND TDM_STATUS <> 2
Все еще имеет значения = False3. Не обращайте на это внимания! Идентификатор класса 862 не имеет строк. 853, похоже, это сработало. Спасибо!!!!
4. Рад, что это сработало. Я также обновил свой пример для 4-значных лет. Я (позже) понял, что я поднял свой пример из реализации, которая специально требовала 2-значных лет (тьфу!).
5. Насколько я помню, это соглашение OLEDB / ODBC, и фактический драйвер OLEDB не будет преобразован в date, если он не находится внутри #31-May-2009 #. Таким образом, драйвер сообщает базе данных, что это символы, не имеющие даты.
Ответ №2:
1) Вы создаете запрос, который не использует переменные привязки? Или вы вручную заполняете переменные привязки в своем отладочном выводе для нас? Если вы не используете переменные привязки, вы реально создадите серьезную проблему с производительностью в своей базе данных, потому что вы уничтожите общий пул Oracle. Вы собираетесь создать небезопасный код, который уязвим для атак с использованием SQL-инъекций. И в конечном итоге вы потратите много времени на устранение ошибок, связанных с типами данных, экранирующими строками и т. Д..
Если бы вы использовали переменные привязки, вы бы просто создали локальные переменные даты в вашем VB.Сетевое приложение, привяжите их к вашему запросу, и все, как правило, будет работать. Это было бы намного эффективнее, поскольку Oracle нужно было бы выполнить жесткий синтаксический анализ инструкции только один раз и не заполнять общий пул похожими инструкциями при повторном запуске запроса с разными датами.
Я не являюсь разработчиком VB. Но если вы используете переменные привязки, вы должны заменить литералы в вашем SQL-операторе заполнителями, т. е.
AND TDM_END_TIME >= :early_time
AND TDM_END_TIME < :late_time
AND TDM_STATUS <> :status_1
AND TDM_STATUS <> :status_2
Затем вы должны предоставить значения для этих переменных привязки во время выполнения, т.е.
flowQueryCMD.Parameters.Add( ":early_time", <<your VB date object>> )
flowQueryCMD.Parameters.Add( ":late_time", <<your VB date object>> )
Наконец, вы выполняете запрос
2) Если вы не используете переменные привязки, то вы должны убедиться, что ваши типы данных совпадают. ’01-Jan-2009′ — это строка, а не дата, поэтому Oracle должен неявно преобразовать строку в дату. Он делает это с помощью сеанса NLS_DATE_FORMAT
. Если у вас NLS_DATE_FORMAT
не будет значения ‘ДД-ПН-ГГГГ’, преобразование завершится неудачно (или молча сделает что-то неожиданное), и вы не получите ожидаемых результатов. Поскольку значение NLS_DATE_FORMAT
может быть разным для каждого сеанса, вы никогда не должны полагаться на какое-либо конкретное NLS_DATE_FORMAT
значение, установленное в каком-либо конкретном сеансе, иначе ваш код может работать для вас и не работать для вашего коллеги, который предпочитает европейские форматы даты. Ваш код может нормально работать в одном сеансе (скажем, SQL * Plus, который получает его NLS_DATE_FORMAT
из одного места), а не в другом сеансе (скажем, приложение .Net, которое получает настройки языка, набора символов и формата даты из .Чистый стек)
Есть несколько способов указать литералы даты в Oracle. Первый — использовать синтаксис литерала даты ANSI (или литерала метки времени) (обратите внимание, что литералы даты ANSI всегда указываются как ГГГГ-ММ-ДД)
AND tdm_end_time >= date '2009-01-01'
AND tdm_end_time < date '2009-05-31'
Второй вариант — выполнить явное преобразование самостоятельно, используя TO_DATE
функцию
AND tdm_end_time >= to_date( '01-Jan-2009', 'DD-MON-YYYY' )
AND tdm_end_time < to_date( '31-May-2009', 'DD-MON-YYYY' )
Комментарии:
1. 1 за подробности. Будучи новичком в Oracle и его терминологии: не могли бы вы опубликовать пример с переменными Bind, пожалуйста?