我们有很多查询,我们需要根据任意数量的给定过滤器动态地使用where子句。过滤器源自用户输入(超出此问题的范围)。
我们提出了如下所示的解决方案:
过滤器在代码中由带有零个或多个元素的列表(plsql表)和一个包含列表长度的count变量表示,如果列表应该被忽略,则为-1(不要过滤)
示例:
CREATE OR REPLACE TYPE t_number_table AS TABLE OF NUMBER;
PROCEDURE get_filter(p_filter_type IN VARCHAR2,
p_key_list OUT t_number_table,
p_count OUT PLS_INTEGER) IS
BEGIN
--normally, this procedure would consult the user input to find out what needs
--to be filtered, but for this example just always return the same filters
CASE p_filter_type
WHEN 'ORDER' THEN
p_key_list := t_number_table(11, 12, 13, 14);
p_count := 4; --user filtered on 4 orders
WHEN 'PRODUCT' THEN
p_key_list := NULL;
p_count := -1; --user did not filter on product
WHEN 'CUSTOMER' THEN
p_key_list := t_number_table(1000);
p_count := 1; --user filtered on 1 customer
END CASE;
END;
此get_filter
程序会返回用户在四个订单上过滤时的过滤器,不会过滤产品并过滤一个客户。
如果我们想获得与这些过滤器匹配的订单集,我们按如下方式使用它:
DECLARE
v_order_list t_number_table;
v_order_count PLS_INTEGER;
v_product_list t_number_table;
v_product_count PLS_INTEGER;
v_customer_list t_number_table;
v_customer_count PLS_INTEGER;
BEGIN
get_filter('ORDER', v_order_list, v_order_count);
get_filter('PRODUCT', v_product_list, v_product_count);
get_filter('CUSTOMER', v_customer_list, v_customer_count);
...
OPEN some_ref_cursor FOR
SELECT *
FROM order_header oh
JOIN order_line ol ON ol.orderno = oh.orderno
WHERE (v_order_count = -1 OR
oh.orderno IN (SELECT * FROM TABLE(v_order_list)))
AND (v_product_count = -1 OR
ol.productno IN (SELECT * FROM TABLE(v_product_list)))
AND (v_customer_count = -1 OR
oh.customerno IN (SELECT * FROM TABLE(v_customer_list)));
END;
我们对我们的方法感兴趣的是它非常灵活,有点优雅。它似乎也表现不错,但我想知道别人如何处理这个问题。此外,我们错过的方法可能存在一些问题。对这种方法有什么缺点?