Октава: как получить данные из объекта Java ResultSet? - PullRequest
1 голос
/ 01 апреля 2019

Мне нужно заполнить свой экземпляр Octave данными, полученными из базы данных Oracle.

Я установил соединение OJDBC в своем экземпляре Octave, и теперь я могу помещать данные из базы данных Oracle в Java ResultSet.объект в октаве (взят из: https://lists.gnu.org/archive/html/help-octave/2011-08/msg00250.html):

javaaddpath('access-path-to-ojdbc8.jar') ;
props = javaObject('java.util.Properties') ;
props.setProperty("user", 'username') ;
props.setProperty("password", 'password') ;
driver = javaObject('oracle.jdbc.OracleDriver') ;
url = 'jdbc:oracle:thin:@ip:port:schema' ;
con = driver.connect(url, props) ;
sql = 'select-query' ;
ps = con.prepareStatement(sql) ;
rs = ps.executeQuery() ;

, но не удалось получить данные из этого ResultSet.

Как поместить данные из объекта ResultSet в Octave вмассив или матрица?

Ответы [ 2 ]

0 голосов
/ 20 апреля 2019

Узнайте, что делать

Документы, которые вы хотите ResultSet и связанные с ними классы, содержатся в документации Java JDBC API . (Вам не нужен специфичный для Oracle документ, если вы не хотите делать причудливые специфичные для Oracle вещи. Все драйверы JDBC соответствуют универсальному API JDBC.) Ознакомьтесь с этим и любым учебным пособием по JDBC; поскольку это объект Java, вы будете использовать те же вызовы методов из Octave, что и из кода Java.

Для преобразования в значения Octave следует знать, что примитивы Java автоматически преобразуются в типы Octave, java.lang.String объекты требуют преобразования, вызывая для них char(...) и значения java.sql.Date, которые вам придется преобразовать в datenums вручную. (Ленивый способ - получить их строковые значения и проанализировать их; быстрый способ - получить их значения времени Unix и преобразовать их численно.)

Что делать

Поскольку Java JDBC продвигает курсор результирующего набора по одной строке за раз и требует отдельного вызова метода для получения значения для каждого столбца, необходимо использовать пару вложенных циклов для итерации по ResultSet. Как это:

rsMeta = rs.getMetaData();
nCols = rsMeta.getColumnCount();
data = NaN(1, nCols);
iRow = 0;
while rs.next()
  iRow = iRow + 1;
  for iCol = 1:nCols
    data(iRow,iCol) = rs.getDouble(iCol);
  endfor
endwhile

Ах, а что если ваши столбцы не все числовые? Затем вам нужно взглянуть на тип столбца в rsMeta, включить его и использовать массив ячеек для хранения гетерогенного набора данных. Как это:

rsMeta = rs.getMetaData();
nCols = rsMeta.getColumnCount();
data = cell(1, nCols);
iRow = 0;
while rs.next()
  iRow = iRow + 1;
  for iCol = 1:nCols
    colTypeId = rsMeta.getColumnType(iCol);
    switch colTypeId
      case NUMERIC_TYPE
        data{iRow,iCol} = rs.getDouble(iCol);
      case CHAR_TYPE
        data{iRow,iCol} = rs.getString(iCol);
        data{iRow,iCol} = char(data{iRow,iCol});
      # ... and so on ...
      otherwise
        error('Unsupported SQL data type in column %d: %d', ...
          iCol, colTypeId);
    endswitch
  endfor
endwhile

Откуда вы знаете, какими должны быть значения для NUMERIC_TYPE, CHAR_TYPE и так далее? Вы должны проверить значения в java.sql.Types Java-классе. Сделайте это во время выполнения, чтобы убедиться, что вы согласны с JDK, с которым вы работаете.

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

Как быстро ехать

К сожалению, производительность этого процесса составит большой отсос , потому что вызовы методов Java из Octave дороги, а ячейки неэффективно хранят данные. Если ваши результирующие наборы велики, чтобы получить хорошую производительность, вам нужно написать слой буферизации набора результатов в Java , который запускает циклы в Java и буферизует результаты в примитивных массивах для каждого столбца. и использовать это. Если вам нужен пример того, как это сделать, у меня есть пример реализации в Matlab в моей библиотеке Janklab (слой M-кода здесь ). Не стесняйтесь украсть код. Octave не поддерживает точечные ссылки на конструкторы Java или методы классов, поэтому для преобразования их в Octave вам необходимо заменить все эти вызовы javaObject и javaMethod. (Это утомительно и приводит к ужасному коду, поэтому я не собираюсь делать это сам. Извините.)

Если вы не хотите делать это (и действительно, кто?), И все еще нуждаетесь в хорошей производительности, вам нужно на самом деле сделать - забыть о подключении Octave напрямую к Oracle и написать отдельная программа Python / NumPy или R, которая принимает ваш запрос, запускает его для вашей базы данных Oracle и записывает результат в файл .mat, который вы затем прочитаете из Octave.

0 голосов
/ 02 апреля 2019

У меня нет доступа к указанному .jar или подходящей базе данных для проверки вашего конкретного кода, но в любом случае это не проблема октавы. Для эффективной работы вам необходим соответствующий API для класса ResultSet и стандартный подход к его обработке. Оракул документация предполагает, что в Java вы должны сделать что-то вроде этого:

while (rs.next()) { System.out.println (rs.getString(1)); }

Итак, предположительно, это именно то, что вы будете делать в октаве, кроме как через java-интерфейс октавы. Один из возможных способов, которым это может выглядеть, -

while rs.next().booleanValue  % since a Boolean java object by itself
                              % isn't valid logical input for octave's
                              % 'while' statement
    % do something with rs, e.g. fill in a cell array
endwhile

Что касается того, можете ли вы автоматически преобразовывать массив Java в объект-ячейку октавы или наоборот, насколько я знаю, это невозможно. Вам нужно было бы установить / получить элементы от одного к другому через цикл for, как вы это делали бы в java (например, см. Примечание в руководстве относительно функции javaArray )

...