2011-09-19 88 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) 
{ 
}