2009-10-05 45 views
0

我正在使用從Java數據庫獲取數據的Java準備語句。由於某些性能問題,查詢使用「虛擬列」作爲索引。準備好的語句 - 將函數用作where子句的一部分

查詢看起來是這樣的:

String status = "processed"; 
String customerId = 123; 
String query = "SELECT DISTINCT trans_id FROM trans WHERE status = " + status + " AND FN_GET_CUST_ID(trans.trans_id) = " + customerId; 

Connection conn = getConnection(); 
PreparedStatement ps = null; 
ResultSet rs = null; 

try { 
    ps = conn.prepareStatement(query); 
    ps.execute(); 
    ... 
} catch (...) 

這是行不通的。將函數作爲where子句的一部分導致SQLException。我知道CallableStatement,並知道我可以先使用它,然後連接結果。但是,該表使用FN_GET_CUST_ID(trans_id)作爲其索引的一部分。有沒有辦法將使用數據庫函數的預準備語句用作查詢參數?

+1

已處理的狀態應引用。也許這就是導致你的例外的原因,不是嗎? – quosoo 2009-10-05 13:57:02

+0

在WHERE子句中有一個函數應該可以工作,你的問題可能在別處。你能發佈錯誤代碼和消息(SQLException.getErrorCode)嗎?查詢實際上在SQL * Plus中工作嗎? – 2009-10-05 13:58:35

+0

對不起,我發佈的示例並未逐字複製。我試圖削減它,以消除很多多餘的非必要的東西。缺少的引號不是問題。 – emulcahy 2009-10-05 15:16:42

回答

6
  1. 不要將SQL的參數連接到字符串中。始終使用佔位符(?)和setXxx(column, value);

  2. 如果您要在您最喜歡的DB工具中運行SQL,則會出現相同的錯誤。問題是Oracle出於某種原因無法使用該功能。你得到什麼錯誤代碼?

+2

對於佔位符的+1 – Powerlord 2009-10-05 14:01:06

+1

問題是該函數沒有公共執行特權。 Aaron評論中的#2「問題在於Oracle由於某種原因無法使用該功能。」是什麼最終導致我發現問題,所以給他信任。 – emulcahy 2009-10-05 16:47:32

0

乍一看,查詢似乎是不正確的。在使用status變量(假設狀態是varchar列)之前和之後,您缺少一個撇號。

String query = "SELECT DISTINCT trans_id FROM trans 
WHERE status = '" + status + "' AND FN_GET_CUST_ID(trans.trans_id) = " + customerId; 

編輯:我不是從java的背景。但是,正如@Aron所說的,最好使用佔位符&,然後使用某種方法爲參數設置值以避免SQL Injection

+0

這是正確的,正如我在對問題的第一條評論中指出的那樣。但是,在使用Aaron提到的查詢語句中使用佔位符可能更好 - 否則使用PreparedStatement不會帶來好處。 – quosoo 2009-10-05 14:08:53

1

如果客戶ID是數字,則保留int而不是String。然後嘗試執行以下操作:

String query = "SELECT DISTINCT trans_id FROM trans WHERE status = ? AND FN_GET_CUST_ID(trans.trans_id) = ?"; 

ps = conn.prepareStatement(query); 
ps.setString(1, status); 
ps.setInt(2, customerId); 
ps.execute(); 

除了準備好的聲明中的其他好處,你將不必記住字符串報價(這會導致你的錯誤很可能)以及特殊字符轉義。