我有一个接受多个参数的存储过程(即pName,pHeight,pTeam)
我建立了这样的查询:
SQLQuery VARCHAR2(6000);
TestCursor T_CURSOR;
SQLQuery := 'SELECT ID, Name, Height, Team FROM MyTable WHERE ID IS NOT NULL ';
-- Build the query based on the parameters passed.
IF pName IS NOT NULL
SQLQuery := SQLQuery || 'AND Name LIKE :pName ';
END IF;
IF pHeight IS > 0
SQLQuery := SQLQuery || 'AND Height = :pHeight ';
END IF;
IF pTeam IS NOT NULL
SQLQuery := SQLQuery || 'AND Team LIKE :pTeam ';
END IF;
OPEN TestCursor FOR SQLQuery USING pName, pHeight, pTeam;
如果我执行传递所有参数的过程,它将正常运行。
但是如果我只传递了一个或两个参数,则程序错误输出:
ORA-01006: bind variable does not exist
如何根据参数值的使用位置有选择地将变量与参数绑定?例如,如果只传递了pName,那么我只会执行查询:
OPEN TestCursor FOR SQLQuery USING pName;
或者如果pName和pTeam都通过了,那么:
OPEN TestCursor FOR SQLQuery USING pName, pTeam;
希望有人能够找到解决这个问题的更多方法。感谢。
编辑: 我实际上可以使用以下内容:
- 根据传递的参数构建查询。 如果pName不是NULL SQLQuery:= SQLQuery || '和名字一样'''|| pName || '''; 结束如果;
IF pHeight IS > 0
SQLQuery := SQLQuery || 'AND Height = pHeight ';
END IF;
IF pTeam IS NOT NULL
SQLQuery := SQLQuery || 'AND Team LIKE ''' || pTeam || ''' ';
END IF;
OPEN TestCursor FOR SQLQuery;
但是这非常容易受到SQL注入......
答案 0 :(得分:9)
您可以使用DBMS_SQL包。这提供了另一种运行动态SQL的方法。使用起来可能稍微麻烦一点,但它可以更灵活,特别是使用不同数量的绑定参数。
以下是你如何使用它(警告:我没有测试过这个):
FUNCTION player_search (
pName IN VARCHAR2,
pHeight IN NUMBER,
pTeam IN VARCHAR2
) RETURN SYS_REFCURSOR
IS
cursor_name INTEGER;
ignore INTEGER;
id_var MyTable.ID%TYPE;
name_var MyTable.Name%TYPE;
height_var MyTable.Height%TYPE;
team_var MyTable.Team%TYPE;
BEGIN
-- Put together SQLQuery here...
-- Open the cursor and parse the query
cursor_name := DBMS_SQL.OPEN_CURSOR;
DBMS_SQL.PARSE(cursor_name, SQLQuery, DBMS_SQL.NATIVE);
-- Define the columns that the query returns.
-- (The last number for columns 2 and 4 is the size of the
-- VARCHAR2 columns. Feel free to change them.)
DBMS_SQL.DEFINE_COLUMN(cursor_name, 1, id_var);
DBMS_SQL.DEFINE_COLUMN(cursor_name, 2, name_var, 30);
DBMS_SQL.DEFINE_COLUMN(cursor_name, 3, height_var);
DBMS_SQL.DEFINE_COLUMN(cursor_name, 4, team_var, 30);
-- Add bind variables depending on whether they were added to
-- the query.
IF pName IS NOT NULL THEN
DBMS_SQL.BIND_VARIABLE(cursor_name, ':pName', pName);
END IF;
IF pHeight > 0 THEN
DBMS_SQL.BIND_VARIABLE(cursor_name, ':pHeight', pHeight);
END IF;
IF pTeam IS NOT NULL THEN
DBMS_SQL.BIND_VARIABLE(cursor_name, ':pTeam', pTeam);
END IF;
-- Run the query.
-- (The return value of DBMS_SQL.EXECUTE for SELECT queries is undefined,
-- so we must ignore it.)
ignore := DBMS_SQL.EXECUTE(cursor_name);
-- Convert the DBMS_SQL cursor into a PL/SQL REF CURSOR.
RETURN DBMS_SQL.TO_REFCURSOR(cursor_name);
EXCEPTION
WHEN OTHERS THEN
-- Ensure that the cursor is closed.
IF DBMS_SQL.IS_OPEN(cursor_name) THEN
DBMS_SQL.CLOSE_CURSOR(cursor_name);
END IF;
RAISE;
END;
(注意:DBMS_SQL.TO_REFCURSOR
是Oracle 11g中的新功能。)
答案 1 :(得分:7)
这并不是非常优雅,但它意味着你总是可以提供所有三个绑定变量,即使它们中的一些是null。如果需要,您只需添加额外的WHERE
子句。
(我尝试格式化动态SQL以使其更具可读性,您可以将其作为一个长字符串提供。)
FUNCTION myFunc (
pName IN VARCHAR2,
pHeight IN VARCHAR2,
pTeam IN VARCHAR2
)
RETURN T_CURSOR
IS
-- Local Variables
SQLQuery VARCHAR2(6000);
TestCursor T_CURSOR;
BEGIN
-- Build SQL query
SQLQuery := 'WITH t_binds '||
' AS (SELECT :v_name AS bv_name, '||
' :v_height AS bv_height, '||
' :v_team AS bv_team '||
' FROM dual) '||
' SELECT id, '||
' name, '||
' height, '||
' team '||
' FROM MyTable, '||
' t_binds '||
' WHERE id IS NOT NULL';
-- Build the query WHERE clause based on the parameters passed.
IF pName IS NOT NULL
THEN
SQLQuery := SQLQuery || ' AND Name LIKE bv_name ';
END IF;
IF pHeight > 0
THEN
SQLQuery := SQLQuery || ' AND Height = bv_height ';
END IF;
IF pTeam IS NOT NULL
THEN
SQLQuery := SQLQuery || ' AND Team LIKE bv_team ';
END IF;
OPEN TestCursor
FOR SQLQuery
USING pName,
pHeight,
pTeam;
-- Return the cursor
RETURN TestCursor;
END myFunc;
我不在具有数据库访问权限的工作站前面,所以我无法测试该功能但它应该接近(请原谅任何语法错误,这是漫长的一天!)
希望它有所帮助...
答案 2 :(得分:1)
我使用的方法是在动态SQL中包含一个ELSE情况,其状态与IF相反。您的代码测试pName不为null,因此我将在生成的查询中添加一个子句,测试pName是否为Null。这样,您每次都可以传递相同的参数,而不会影响查询结果。
SQLQuery VARCHAR2(6000);
TestCursor T_CURSOR;
SQLQuery := 'SELECT ID, Name, Height, Team FROM MyTable WHERE ID IS NOT NULL ';
-- Build the query based on the parameters passed.
IF pName IS NOT NULL
SQLQuery := SQLQuery || 'AND Name LIKE :pName ';
ELSE
SQLQuery := SQLQuery || 'AND :pName IS NULL';
END IF;
IF pHeight IS > 0
SQLQuery := SQLQuery || 'AND Height = :pHeight ';
ELSE
SQLQuery := SQLQuery || 'AND :pHeight <=0 ';
END IF;
IF pTeam IS NOT NULL
SQLQuery := SQLQuery || 'AND Team LIKE :pTeam ';
ELSE
SQLQuery := SQLQuery || 'AND :pTeam IS NULL';
END IF;
OPEN TestCursor FOR SQLQuery USING pName, pHeight, pTeam;
答案 3 :(得分:0)
怎么样
SQLQuery := 'SELECT ID, Name, Height, Team FROM MyTable WHERE ID IS NOT NULL ';
SQLQuery := SQLQuery || 'AND Name LIKE :pName ';
SQLQuery := SQLQuery || 'AND Team LIKE :pTeam ';
SQLQuery := SQLQuery || 'AND (Height = :pHeight OR :pHeight = 0)';
OPEN TestCursor FOR SQLQuery USING nvl(pName, '%'), nvl(pTeam, '%'), nvl(pHeight, 0), nvl(pHeight, 0);