2011-09-19 60 views
1

我有jsp頁面,其中用戶選擇表名稱,列名稱和列值,這三個條件我想從數據庫中刪除所有匹配的行。有沒有辦法在oracle中傳遞表名,列名和列值以從表中刪除特定行?任何示例將幫助我。謝謝通過傳遞表名稱和列名稱從Oracle表中刪除行

+0

您可能必須使用動態SQL,但在這種情況下要非常小心,以防止SQL注入,因爲您正在傳遞的內容可能會導致嚴重的被劫持。 http://download.oracle.com/docs/cd/B28359_01/appdev.111/b28370/dynamic.htm – Ollie

回答

2

我擔心SQL注入攻擊,你提供的是表和列名。 您可以創建一個Oracle函數刪除所需的記錄,並刪除該行之前必須滿足的測試對於某些條件:

CREATE OR REPLACE 
FUNCTION delete_record (
    p_table IN VARCHAR2, 
    p_column IN VARCHAR2, 
    p_value IN VARCHAR2 
) 
RETURN NUMBER 
AS 
    v_table user_tables.table_name%TYPE; 
    v_columns user_tab_cols.column_name%TYPE; 
BEGIN 
    -- Check table exists in DB 
    SELECT table_name 
    INTO v_table 
    FROM user_tables 
    WHERE table_name = UPPER(p_table); 

    -- Check column exists in DB table 
    SELECT column_name 
    INTO v_colums 
    FROM user_tab_cols 
    WHERE table_name = UPPER(p_table) 
     AND column_name = UPPER(p_column); 

    EXECUTE IMMEDIATE 
     'DELETE FROM '||DBMS_ASSERT.SIMPLE_SQL_NAME(p_table)|| 
     ' WHERE '||DBMS_ASSERT.SIMPLE_SQL_NAME(p_column)||' = :col_value' 
    USING p_value; 

    RETURN SQL%ROWCOUNT; 
EXCEPTION 
    WHEN NO_DATA_FOUND 
    THEN 
     -- Either return -1 (error) or log an error etc. 
     RETURN -1; 
    WHEN others 
    THEN 
     <Your exception handling here> 
END delete_record; 
/

本(或像這樣)會檢查所提供的表和列變量的存在數據庫,然後刪除記錄並返回刪除的記錄數。 如果刪除的號碼出現問題,您可以發出回滾語句,如果沒有問題,則可以發出提交。

當然,如果您想提供完全限定的表名(建議),那麼您將使用DBMS_ASSERT.QUALIFIED_SQL_NAME函數而不是DBMS_ASSERT.SIMPLE_SQL_NAME函數。

希望它可以幫助...

編輯:在回答傑克的有關從和日期添加日期的問題。

如果添加的是在傳遞給函數的兩個新條件:

CREATE OR REPLACE 
FUNCTION delete_record (
    p_table  IN VARCHAR2, 
    p_column IN VARCHAR2, 
    p_value  IN VARCHAR2, 
    p_date_from IN DATE, 
    p_date_to IN DATE 
) 

然後,你需要擴大EXECUTE立即用:

EXECUTE IMMEDIATE 
    'DELETE FROM '||DBMS_ASSERT.SIMPLE_SQL_NAME(p_table)|| 
    ' WHERE '||DBMS_ASSERT.SIMPLE_SQL_NAME(p_column)||' = :col_value'|| 
    ' AND date BETWEEN :date_from AND :date_to' 
USING p_value, 
     p_date_from, 
     p_date_to; 

注:這假設你的日期列在表中稱爲「日期」。 我目前沒有SQL界面在我面前,但這應該足夠接近你需要的工作。

如果您將p_date_XXXX參數作爲VARCHAR2而不是DATE類型傳遞,那麼在將值傳遞給動態SQL之前,需要先「TO_DATE」。

例如

EXECUTE IMMEDIATE 
    'DELETE FROM '||DBMS_ASSERT.SIMPLE_SQL_NAME(p_table)|| 
    ' WHERE '||DBMS_ASSERT.SIMPLE_SQL_NAME(p_column)||' = :col_value'|| 
    ' AND date BETWEEN :date_from AND :date_to' 
USING p_value, 
     TO_DATE(p_date_from, <date_format>), 
     TO_DATE(p_date_to, <date_format>); 
+0

我不確定這會停止sql注入:假設表名是「users」,列名是「id 「並且是數字。如果我在p_value中傳遞以下內容會發生什麼:「5 or 1 = 1」? 它會變成類似於:從用戶id = 5或1 = 1刪除 不會從數據庫中刪除所有用戶嗎? –

+0

@ A.J。不,使用列值的綁定變量會阻止您聲明的SQL注入。 (請參閱:http://download.oracle。COM /文檔/ CD/B19306_01/appdev.102/b14251/adfns_dynamic_sql.htm#BJECFFHD)。但從根本上說,OP知道要傳遞給函數的是什麼類型的值,並且使用這些特定的知識可以調整函數以加強它抵禦潛在的威脅。理想情況下,沒有數據庫功能會使用動態SQL來完全保護,但不幸的是,這是一個烏托邦(以我的經驗)很少發生。 – Ollie

+0

謝謝我今天學到了東西:))))) –

1
DELETE FROM table_name WHERE column_name = column_value 

的問題是,你不能在PreparedStatement綁定表或列名,僅列值。

0

應該工作(從內存中,未測試):

Statement stmt = null; 

try 
{ 
    stmt = conn.createStatement("DELETE FROM " + tableName + " WHERE " + columnName + " = '" + condition + "'"); 
    int deleted = stmt.execute(); 
} 
catch (SQLException e) 
{ 
    ... report error 
} 

try 
{ 
    if (stmt != null) 
     stmt.close(); 
} 
catch (SQLException ignore) 
{ 
}