एक स्ट्रिंग> 4k से बनाई गई एक विधेय में ओरेकल क्लोब का उपयोग करें


11

मैं नीचे दिए गए Oracle चयन में प्रयोग किए जाने के लिए> 4000 वर्णों (file_data बाँध चर में आपूर्ति) की एक स्ट्रिंग से एक क्लोब बनाने की कोशिश कर रहा हूँ:

myQuery=
select *
from dcr_mols
WHERE flexmatch(ctab,:file_data,'MATCH=ALL')=1;

अगर मैं TO_CLOB () राउंड file_data जोड़ता हूं तो यह एक varchar के लिए बदनाम Oracle 4k सीमा को विफल करता है (यह <4k स्ट्रिंग्स के लिए ठीक है)। त्रुटि (SQL डेवलपर में) है:

ORA-01460: unimplemented or unreasonable conversion requested
01460. 00000 -  "unimplemented or unreasonable conversion requested"

FYI करें फ्लेक्समैच फ़ंक्शन का उपयोग अणुओं की खोज के लिए किया जाता है, और यहाँ वर्णित है: http://help.accelrysonline.com/ulm/onelab/1.0/content/ulm_pdfs/direct/developers/direct/2016_developersguide.pdf

फ़ंक्शन स्वयं थोड़ा जटिल है, लेकिन सार यह है कि 2 पैरामीटर एक क्लोब होना है। तो मेरा सवाल यह है कि मैं एक जावा स्ट्रिंग bind_variable 4000 से अधिक वर्णों को sql (या जावा) में एक क्लोब में कैसे परिवर्तित करूं।

मैंने जावा (स्प्रिंग बूट 2) का उपयोग करते हुए नीचे की विधि (जो कि क्लोब्स डालने पर काम करता है) की कोशिश की:

MapSqlParameterSource parameters = new MapSqlParameterSource();
parameters.addValue("file_data", fileDataStr,Types.CLOB);
jdbcNamedParameterTemplate.query(myQuery,parameters,…

यह तरीका काम करना चाहिए लेकिन यह एक परिवर्तित फ्लेक्समैच त्रुटि के साथ विफल हो जाता है जो 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"

ध्यान दें कि मैं स्प्रिंगबूट 2 का उपयोग कर रहा हूं, लेकिन मैं OracleConnection (मेरे स्प्रिंग NamedParametersJdbcTemplate ऑब्जेक्ट से प्राप्त) का उपयोग करके किसी भी विधि को प्राप्त नहीं कर सकता (यहां तक ​​कि लौंग <4k पर), इसलिए मुझे संदेह है कि मैंने कुछ बेवकूफ किया है। मैंने कोशिश की:

 @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);

आवेदन:

spring.datasource.url=jdbc:oracle:thin:@//${ORA_HOST}:${ORA_PORT}/${ORA_SID}
spring.datasource.username=${ORA_USER}
spring.datasource.password=${ORA_PASS}

ध्यान दें कि यह ठीक काम करता है अगर मैं पुराने स्कूल में जाता हूं और एक गैर वसंत कनेक्शन के साथ-साथ एक रेडीस्टेटमेंट का उपयोग करता हूं, जिसमें एक सेट क्लोब () विधि है:

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();

लेकिन मैं जावा या एसक्यूएल में एक स्प्रिंग 2 समाधान पसंद करूंगा। कोई मदद, सुझाव की सराहना की


यह काफी अच्छा सवाल है +1, जो मैंने अब तक किया है उससे अलग है। क्या आप flexmatch()फ़ंक्शन के लिए एपीआई डॉक्स को इंगित कर सकते हैं ? मैं इसकी आवश्यकता देखना चाहूंगा। ईमानदार, मैंने WHEREखंड में बड़े मानों को मापदंडों के रूप में कभी इस्तेमाल नहीं किया । मैंने INSERTउनका उपयोग किया है, मैंने उनका उपयोग करके पुनः प्राप्त किया है SELECT। आपका मामला अलग है।
इम्पेलर

@The_impaler प्रश्न में डॉक्स का लिंक है। यह एक एपीआई डर नहीं है, लेकिन यह हमारे पास है। यह बहुत ही आला फंक्शन है। आवश्यकता है मैं एक अणु के डिजिटल प्रतिनिधित्व को खोज रहा हूं, और आपको ऐसा करने के लिए एक विशेषज्ञ फ़ंक्शन की आवश्यकता है। इसका मतलब यह है कि dcr_mols तालिका में मैं पहले से ही मौजूद है।
डी.एस.

आप किस Oracle संस्करण का उपयोग कर रहे हैं?
16

@ आरियस ओजडबेक 6-11.2.1.0.1
डीएस।

जवाबों:


5

इसे स्ट्रीम करें। आप एक एसक्यूएल बयान में सिर्फ एक बड़ा मूल्य पेस्ट नहीं कर सकते।

आपको इसकी आवश्यकता होगी:

  • INSERTकथन में खाली BLOB डालें (EMPTY_BLOB () का उपयोग कर? ... काफी याद नहीं है)।
  • खाली बूँद के लिए आउटपुट स्ट्रीम प्राप्त करें।
  • फिर फ़ाइल से एक इनपुट स्ट्रीम प्राप्त करें। कृपया पूरी फ़ाइल को मेमोरी में लोड न करें।
  • फिर बफरिंग का उपयोग करके इनपुट स्ट्रीम से आउटपुट स्ट्रीम में ब्लॉक ट्रांसफर करें। एक 16 KB बफर करना चाहिए।
  • दोनों धाराओं को बंद करें।

यह ओरेकल में बड़े पैमाने पर डेटा से निपटने का मानक तरीका है। बहुत सारे उदाहरण हैं।

बड़े पैमाने पर डेटा ( BLOBऔर CLOBप्रकार) प्राप्त करना उसी तरह से काम करता है। बस उस मामले में InputStream का उपयोग करें।


@ The_impaler मैं एक लौंग नहीं डाल रहा हूँ। मैं एक क्लॉब को फंक्शन में सप्लाई कर रहा हूं, जिसे चुनिंदा
DS

1

"BIOVIA Direct" API के प्रलेखन को पढ़ना, पृष्ठ 27 पर एक दिलचस्प उदाहरण है, जो नीचे दिखाया गया है:

select ...
from ...
where flexmatch(
ctab,
(select ctab from nostruct_table),
'all'
)=1

यह पहले से लोड किए गए CLOB का उपयोग करता है । इसलिए मुझे लगता है कि एक सभ्य-पर्याप्त समाधान CLOB को आपकी एक तालिका में लोड करना होगा (या उन सभी को पहले से लोड करना होगा), और फिर बस उनका उपयोग करें।

चरण # 1 - अपने CLOB को एक तालिका में लोड करें:

create table mol_file (
  id number(12) primary key not null,
  content clob
);

insert into mol_file (id, content) values (:id, :content);

और CLOB प्रविष्टि (शायद धाराओं का उपयोग करके) करने के लिए अपने जावा कोड का उपयोग करें जैसा कि एक अन्य उत्तर (इंटरनेट में बहुत सारे उदाहरण) में दिखाया गया है। उदाहरण के लिए, आईडी = के साथ अपना मोल डेटा कंटेंट डालें 123

चरण # 2 - पहले से भरी हुई मोल फ़ाइल का उपयोग करके अपनी क्वेरी चलाएँ:

select *
from dcr_mols
WHERE flexmatch(
        ctab,
        (select content from mol_file where id = :id),
        'MATCH=ALL'
      ) = 1;

आप पहले या (किसी भी अन्य) भरी हुई फ़ाइल का उपयोग :idकरने के 123लिए पैरामीटर सेट कर सकते हैं ।


@ The_impaler धन्यवाद, लेकिन यह एक अखरोट को खुरचने के लिए थोड़ा सा है। हमारे पास चलाने के लिए बहुत सारी क्वेरीज़ हैं और यह कोड को जटिल बनाता है और चीजों को धीमा कर देता है। मैंने अपने प्रश्न को अपडेट किया है, एक पुराने स्कूल के उत्तर के साथ, जिसका मैं अनिच्छा से उपयोग करूंगा यदि कुछ भी बेहतर नहीं होता है।
डी.एस.

1

आप अपने पुराने फैशन फंक्शन को इस तरह कह सकते हैं। ResultSet को संभालने के लिए एक क्लास बनाएं

 class MyPreparedStatementCallback implements PreparedStatementCallback {
    public Object doInPreparedStatement(PreparedStatement preparedStatement)
            throws SQLException, DataAccessException {
        ResultSet rs = preparedStatement.executeQuery();
        List result = new LinkedList();
        rs.close();
        return result;
    }
}

और अपनी विधि में JdbcTemplate का उपयोग करके अपनी क्वेरी को कॉल करें

 jdbcTemplate.execute(new PreparedStatementCreator() {
        @Override
        public PreparedStatement createPreparedStatement(Connection connection)

                throws SQLException, DataAccessException {

            PreparedStatement ps = connection.prepareStatement("select dcr_number from dcr_mols WHERE flexmatch(ctab,?,'MATCH=ALL')=1");
            Clob myClob =  connection.createClob();
            myClob.setString( 1, fileDataStr);
            MapSqlParameterSource parameters = new MapSqlParameterSource();
            parameters.addValue("file_data", myClob, Types.CLOB);
            ps.setClob(1,myClob);
            return ps;

        };
    }, new MyPreparedStatementCallback());

1

मुझे एक रेडीस्टेमेंट का उपयोग करने के लिए वापस लौटना पड़ा, लेकिन मैंने स्प्रिंग से कनेक्शन प्राप्त करके सामान्य कार्यान्वयन को थोड़ा सुधार दिया है और Apache commons BeanListHandler का उपयोग करके ऑब्जेक्ट सूची में ResultSet को मैप किया है

import org.apache.commons.dbutils.ResultSetHandler;
import org.apache.commons.dbutils.handlers.BeanListHandler;

@Autowired
NamedParameterJdbcTemplate  jdbcTemplate;

List<MyDao> myMethod(String fileData){
    String myQuery="select * from dcr_mols WHERE flexmatch(ctab,?,'MATCH=ALL')=1";

try {
    Connection conn =  this.jdbcTemplate.getJdbcTemplate().getDataSource().getConnection().unwrap(OracleConnection.class);   // Get connection from spring

    Clob myClob =  conn.createClob();   // Open a dB clob 
    myClob.setString( 1, fileData);     // add data to clob
    PreparedStatement ps = conn.prepareStatement(myQuery);
    ps.setClob(1,myClob);              // Add a clob into the PreparedStatement
    ResultSet rs =ps.executeQuery();   // Execute the prepared statement

    //ResultSetHandler<List<MyDao>> handler = new BeanListHandler<MyDao>(MyDao.class);   // Define the ResultSet handler
    ResultSetHandler<List<MyDao>> handler = new BeanListHandler<MyDao>(MyDao.class, new BasicRowProcessor(new GenerousBeanProcessor()));  // This is better than the above handler , because GenerousBeanProcessor removes the requirement for the column names to exactly match the java variables

    List<MyDao> myDaoList = handler.handle(rs);   // Map ResultSet to List of MyDao objects
    }catch (Exception e) {
        e.printStackTrace();
    }

return myDaoList;
}

0

आप फ़ाइल डेटा को घोषित कर सकते हैं जैसे कि कनेक्शन का उपयोग करते हुए CLOB के रूप में

java.sql.Clob fileDataStr = oracle.sql.CLOB.createTemporary
(con, false, oracle.sql.CLOB.DURATION_SESSION);

और फिर इसे नीचे की तरह उपयोग करें

 parameters.addValue("file_data", fileDataStr,Types.CLOB);

इसके अलावा, यदि आप अपने कनेक्शन स्ट्रिंग में सेवा नाम के बजाय SID का उपयोग कर रहे हैं, तो अपनी संपत्ति फ़ाइल को नीचे की तरह बदलने का प्रयास करें

spring.datasource.url=jdbc:oracle:thin:@//${ORA_HOST}:${ORA_PORT}:${ORA_SID}

धन्यवाद, लेकिन यह बहुत अजीब है। डेटा किसी भी आकार का हो सकता है इसलिए मुझे विखंडू को बनाने के लिए गतिशील sql का उपयोग करना होगा, साथ ही, यह भी सुनिश्चित नहीं करें कि आप इस तरह से भागों में एक क्लॉब को तोड़ सकते हैं।
डी.एस.

FileDataStr का प्रकार क्या है
psaraj12

यह एक जावा स्ट्रिंग है
डीएस।

क्या आप इसे CLOB और java.sql.Clob fileDataStr = oracle.sql.CLOB.create के रूप में घोषित कर सकते हैं
Psajaj12

मेरे उदाहरण को कमेंट में कैसे बताएं कि फाइलटास्टार को CLOB के रूप में देखें कि कोन कनेक्शन है
psaraj12
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.