4

私の質問は次のとおりです:ORA-01704: string literal too long sを使用して挿入 (またはクエリで何かを実行) するときのエラーをどのように回避しますCLOBか?

次のようなクエリが必要です。

INSERT ALL
   INTO mytable VALUES ('clob1')
   INTO mytable VALUES ('clob2') --some of these clobs are more than 4000 characters...
   INTO mytable VALUES ('clob3')
SELECT * FROM dual;

実際の値で試してみるとORA-01704: string literal too long戻ってきますが。これは非常に明白ですが、どうすれば clob を挿入できますか (または clob を使用して任意のステートメントを実行できますか)?

この質問を見てみましたが、探しているものが含まれていないと思います。私が持っているクロブは a にList<String>あり、それらを繰り返し処理してステートメントを作成します。私のコードは次のとおりです。

private void insertQueries(String tempTableName) throws FileNotFoundException, DataException, SQLException, IOException {
String preQuery = "  into " + tempTableName + " values ('";
String postQuery = "')" + StringHelper.newline;
StringBuilder inserts = new StringBuilder("insert all" + StringHelper.newline);
List<String> readQueries = getDomoQueries();
for (String query : readQueries) {
  inserts.append(preQuery).append(query).append(postQuery);
}
inserts.append("select * from dual;");

DatabaseController.getInstance().executeQuery(databaseConnectionURL, inserts.toString());

}

public ResultSet executeQuery(String connection, String query) throws DataException, SQLException {
  Connection conn = ConnectionPool.getInstance().get(connection);
  Statement stmt = conn.createStatement();
  ResultSet rs = stmt.executeQuery(query);
  conn.commit();
  ConnectionPool.getInstance().release(conn);
  return rs;
}
4

6 に答える 6

8

あなたはそれを複雑にしています。

リスト内の各 clob に対して PreparedStatement と addBatch() を使用します。

String sql = "insert  into " + tempTableName + " values (?)";
PreparedStatement stmt = connection.prepareStatement(sql);
for (String query : readQueries) {
  stmt.setCharacterStream(1, new StringReader(query), query.lenght());
  stmt.addBatch();
}
stmt.exececuteBatch();

エスケープ文字列をいじったり、リテラルの長さに問題がなかったり、一時的な clob を作成したりする必要はありません。おそらく、単一の INSERT ALL ステートメントを使用するのと同じくらい高速です。

現在のドライバー (> 10.2) を使用している場合は、setCharacterStream() 呼び出しと Reader の作成も必要ないと思います。シンプルなsetString(1, query)ものもおそらくうまくいくでしょう。

于 2012-05-23T22:11:48.187 に答える
2

BLOB (バイナリ ラージ オブジェクト) と CLOB (キャラクタ ラージ オブジェクト) は特別なデータ型であり、オブジェクトまたはテキストの形式でデータの大きなチャンクを保持できます。Blob および Clob オブジェクトは、オブジェクトのデータをストリームとしてデータベースに永続化します。

コードの例:

public class TestDB { 
    public static void main(String[] args) { 
        try { 
            /** Loading the driver */ 
            Class.forName("com.oracle.jdbc.Driver"); 

            /** Getting Connection */ 
            Connection con = DriverManager.getConnection("Driver URL","test","test"); 

            PreparedStatement pstmt = con.prepareStatement("insert into Emp(id,name,description)values(?,?,?)"); 
            pstmt.setInt(1,5); 
            pstmt.setString(2,"Das"); 

            // Create a big CLOB value...AND inserting as a CLOB 
            StringBuffer sb = new StringBuffer(400000); 

            sb.append("This is the Example of CLOB .."); 
            String clobValue = sb.toString(); 

            pstmt.setString(3, clobValue); 
            int i = pstmt.executeUpdate(); 
            System.out.println("Done Inserted"); 
            pstmt.close(); 
            con.close(); 

            // Retrive CLOB values 
            Connection con = DriverManager.getConnection("Driver URL","test","test"); 
            PreparedStatement pstmt = con.prepareStatement("select * from Emp where id=5"); 
            ResultSet rs = pstmt.executeQuery(); 
            Reader instream = null; 

            int chunkSize; 
            if (rs.next()) { 
                String name = rs.getString("name"); 
                java.sql.Clob clob = result.getClob("description") 
                StringBuffer sb1 = new StringBuffer(); 

                chunkSize = ((oracle.sql.CLOB)clob).getChunkSize(); 
                instream = clob.getCharacterStream(); 
                BufferedReader in = new BufferedReader(instream); 
                String line = null; 
                while ((line = in.readLine()) != null) { 
                    sb1.append(line); 
                } 

                if (in != null) { 
                    in.close(); 
                } 

                // this is the clob data converted into string
                String clobdata = sb1.toString();  
            } 
        } catch (Exception e) { 
            e.printStackTrace(); 
        } 
    } 
} 
于 2012-10-06T17:04:35.957 に答える
2

文字列連結を使用して SQL ステートメントを作成するのではなく、バインド変数を使用する必要があります。これは、SQL インジェクション攻撃のリスクを軽減し、Oracle が SQL ステートメントのハード解析に費やす時間を減らし、セキュリティ、パフォーマンス、および堅牢性の観点からも有益です。無効な SQL ステートメントが生成される原因となる文字列内の特殊文字 (つまり、一重引用符) です。

私はあなたが次のようなものが欲しいと思っています

private void insertQueries(String tempTableName) throws FileNotFoundException, DataException, SQLException, IOException {
  String preQuery = "  into " + tempTableName + " values (?)" + StringHelper.newline;
  StringBuilder inserts = new StringBuilder("insert all" + StringHelper.newline);
  List<String> readQueries = getDomoQueries();
  for (String query : readQueries) {
    inserts.append(preQuery);
  }
  inserts.append("select * from dual");

  Connection conn = ConnectionPool.getInstance().get(connection);
  PreparedStatement pstmt = conn.prepareStatement(
        inserts);
  int i = 1;
  for (String query : readQueries) {
    Clob clob = CLOB.createTemporary(conn, false, oracle.sql.CLOB.DURATION_SESSION);
    clob.setString(i, query);
    pstmt.setClob(i, clob);
    i = i + 1;
  }
  pstmt.executeUpdate();
}
于 2012-05-23T20:52:51.670 に答える
2

オラクルのドキュメントより

大規模データの入力モードの次の自動切り替えに注意する必要があります。入力モードには、ダイレクト バインディング、ストリーム バインディング、LOB バインディングの 3 つがあります。

PL/SQL ステートメントの場合

setBytes および setBinary ストリーム メソッドは、32767 バイト未満のデータに対して直接バインディングを使用します。

setBytes および setBinaryStream メソッドは、32766 バイトを超えるデータに対して LOB バインディングを使用します。

setString、setCharacterStream、および setAsciiStream メソッドは、データベース文字セットで 32767 バイト未満のデータに対して直接バインディングを使用します。

setString、setCharacterStream、および setAsciiStream メソッドは、データベース文字セットで 32766 バイトを超えるデータに対して LOB バインディングを使用します。

oracle.jdbc.OraclePreparedStatement インタフェースにある setBytesForBlob および setStringForClob メソッドは、任意のデータ サイズに対して LOB バインディングを使用します。

次に、ファイルの内容を PLSQL プロシージャの入力 CLOB パラメータに入れる例を示します。

  public int fileToClob( FileItem uploadFileItem ) throws SQLException, IOException
  {
    //for using stmt.setStringForClob method, turn the file to a big String 
    FileItem item = uploadFileItem;
    InputStream inputStream = item.getInputStream();
    InputStreamReader inputStreamReader = new InputStreamReader( inputStream ); 
    BufferedReader bufferedReader = new BufferedReader( inputStreamReader );    
    StringBuffer stringBuffer = new StringBuffer();
    String line = null;

    while((line = bufferedReader.readLine()) != null) {  //Read till end
        stringBuffer.append(line);
        stringBuffer.append("\n");
    }

    String fileString = stringBuffer.toString();

    bufferedReader.close();         
    inputStreamReader.close();
    inputStream.close();
    item.delete();

    OracleCallableStatement stmt;

    String strFunction = "{ call p_file_to_clob( p_in_clob => ? )}";  

    stmt= (OracleCallableStatement)conn.prepareCall(strFunction);    

    try{    
      SasUtility servletUtility = sas.SasUtility.getInstance();

      stmt.setStringForClob(1, fileString );

      stmt.execute();

    } finally {      
      stmt.close();
    }
  }
于 2012-12-14T20:57:26.937 に答える