Próbuję utworzyć clob z ciągu> 4000 znaków (podanego w zmiennej powiązania file_data) do użycia w predykacie Oracle SELECT poniżej:
myQuery=
select *
from dcr_mols
WHERE flexmatch(ctab,:file_data,'MATCH=ALL')=1;
Jeśli dodam TO_CLOB () okrągłe dane_pliku, nie powiedzie się niesławny limit Oracle 4k dla varchara (jest w porządku dla <4k ciągów). Błąd (w SQL Developer) to:
ORA-01460: unimplemented or unreasonable conversion requested
01460. 00000 - "unimplemented or unreasonable conversion requested"
FYI Funkcja flexmatch służy do wyszukiwania cząsteczek i jest opisana tutaj: http://help.accelrysonline.com/ulm/onelab/1.0/content/ulm_pdfs/direct/developers/direct_2016_developersguide.pdf
Sama funkcja jest nieco skomplikowana, ale istotą jest to, że drugim parametrem musi być clob. Więc moje pytanie brzmi: jak przekonwertować zmienną wiążącą Java String o wartości ponad 4000 znaków na clob w sql (lub Java).
Wypróbowałem poniższą metodę (która działa podczas wstawiania bloków) w Javie (Spring boot 2), używając:
MapSqlParameterSource parameters = new MapSqlParameterSource();
parameters.addValue("file_data", fileDataStr,Types.CLOB);
jdbcNamedParameterTemplate.query(myQuery,parameters,…
Ta metoda powinna działać, ale kończy się niepowodzeniem z skonwertowanym błędem dopasowania elastycznego, który FYI:
SQL state [99999]; error code [29902]; ORA-29902: error in executing ODCIIndexStart() routine\nORA-20100:
MDL-0203: Unable to read from CLOB (csfrm=1, csid=873):
ORA-22922: nonexistent LOB value\nMDL-0021: Unable to copy LOB to string\nMDL-1051: Molstructure search query is not a valid molecule\nMDL-0976:
Molecule index search initialization failed\nORA-06512: at \"C$MDLICHEM80.MDL_MXIXMDL\", line 329\nORA-06512: at \"C$MDLICHEM80.MDL_MXIXMDL\", line 309\n; nested exception is java.sql.SQLException:
ORA-29902: error in executing ODCIIndexStart() routine\nORA-20100: MDL-0203: Unable to read from CLOB (csfrm=1, csid=873):
ORA-22922: nonexistent LOB value\nMDL-0021: Unable to copy LOB to string\nMDL-1051: Molstructure search query is not a valid molecule\nMDL-0976:
Molecule index search initialization failed\nORA-06512: at \"C$MDLICHEM80.MDL_MXIXMDL\", line 329\nORA-06512: at \"C$MDLICHEM80.MDL_MXIXMDL\", line 309\n"
Uwaga: używam SpringBoot 2, ale nie mogę uzyskać żadnej metody przy użyciu OracleConnection (uzyskanej z mojego obiektu Spring NamedParametersJdbcTemplate) do pracy (nawet na blokach <4k), więc podejrzewam, że zrobiłem coś głupiego. Próbowałem:
@Autowired
NamedParameterJdbcTemplate jdbcNamedParameterTemplate;
OracleConnection conn = this.jdbcNamedParameterTemplate.getJdbcTemplate().getDataSource().getConnection().unwrap(OracleConnection.class);
Clob myClob = conn.createClob();
myClob.setString( 1, fileDataStr);
MapSqlParameterSource parameters = new MapSqlParameterSource();
parameters.addValue("file_data", myClob,Types.CLOB);
application.properties:
spring.datasource.url=jdbc:oracle:thin:@//${ORA_HOST}:${ORA_PORT}/${ORA_SID}
spring.datasource.username=${ORA_USER}
spring.datasource.password=${ORA_PASS}
Zauważ, że działa dobrze, jeśli pójdę do starej szkoły i użyję nie-sprężynowego połączenia plus PreparedStatement, który ma metodę setClob ():
OracleDataSource ods = new OracleDataSource();
String url ="jdbc:oracle:thin:@//" + ORA_HOST +":"+ORA_PORT +"/"+ORA_SID;
ods.setURL(url);
ods.setUser(user);
ods.setPassword(passwd);
Connection conn = ods.getConnection();
Clob myClob=conn.createClob();
PreparedStatement ps = conn.prepareStatement("select dcr_number from dcr_mols WHERE flexmatch(ctab,?,'MATCH=ALL')=1");
myClob.setString(1,myMol);
ps.setClob(1,myClob);
ResultSet rs =ps.executeQuery();
Ale wolałbym rozwiązanie Spring 2 w Javie lub Sql. Każda pomoc, sugestie mile widziane.
flexmatch()
funkcji? Chciałbym dostrzec potrzebę tego. Szczerze mówiąc, nigdy nie użyłem dużych wartości jako parametrów wWHERE
klauzuli. Użyłem ichINSERT
i odzyskuję za pomocąSELECT
. Twoja sprawa jest inna.Odpowiedzi:
Przesyłaj strumieniowo. Nie można po prostu wkleić dużej wartości do instrukcji SQL.
Musisz:
INSERT
instrukcji (używając EMPTY_BLOB ()? ... nie całkiem pamiętasz).Jest to standardowy sposób radzenia sobie z ogromnymi danymi w Oracle. Wiele przykładów.
Pobieranie ogromnych danych (
BLOB
iCLOB
typów) działa w ten sam sposób. W takim przypadku wystarczy użyć InputStreams.źródło
Czytając dokumentację API „BIOVIA Direct”, interesujący przykład znajduje się na stronie 27, fragment pokazany poniżej:
Używa już załadowanego CLOB. Dlatego chyba przyzwoitym rozwiązaniem byłoby załadowanie CLOBa do twojej tabeli (lub wstępne załadowanie ich wszystkich z wyprzedzeniem), a następnie po prostu ich użycie.
Krok # 1 - Załaduj CLOB do tabeli:
I użyj kodu Java, aby wykonać wstawianie CLOB (prawdopodobnie przy użyciu strumieni), jak pokazano w innej odpowiedzi (wiele przykładów w Internecie). Na przykład wstaw zawartość danych mol z ID =
123
.Krok # 2 - Uruchom zapytanie, używając już załadowanego pliku mol:
Możesz ustawić
:id
parametr tak,123
aby używał wcześniej załadowanego pliku (lub dowolnego innego).źródło
Możesz tak nazwać swoją starą funkcję mody. utwórz klasę do obsługi zestawu wyników
i wywołaj zapytanie za pomocą JdbcTemplate w swojej metodzie
źródło
Musiałem powrócić do korzystania z PreparedStatement, ale poprawiłem nieco normalną implementację, uzyskując połączenie ze Spring i używając wspólnych apache BeanListHandler do mapowania zestawu wyników na listę obiektów
źródło
Możesz zadeklarować fileDataStr jako CLOB, używając con, który jest połączeniem
a następnie użyj go jak poniżej
Również jeśli używasz SID zamiast nazwy usługi w ciągu połączenia, spróbuj zmienić plik właściwości jak poniżej
źródło