Oracle 在SQL中动态生成WHERE子句,并在不进行硬解析的情况下执行

Oracle 在SQL中动态生成WHERE子句,并在不进行硬解析的情况下执行,oracle,plsql,oracle11g,plsqldeveloper,Oracle,Plsql,Oracle11g,Plsqldeveloper,在SQL中动态生成WHERE子句,并在不进行硬解析的情况下执行 我希望动态构建SQL,添加/更改/删除WHERE条件,直到找到记录。 根据业务规则设置的优先级添加/更改/删除条件 为了更好地描述问题陈述,下面是我的两个表(示例键列),它们的结构如下 表1:-->此表包含提交的每个索赔的索赔相关信息 CLAIM_DOCUMENT -------------- ( HDR_SID NUMBER, PRVDR_NPI NUMBER, INV_TYPE VARCHAR2(4), SPLT

在SQL中动态生成WHERE子句,并在不进行硬解析的情况下执行

我希望动态构建SQL,添加/更改/删除WHERE条件,直到找到记录。 根据业务规则设置的优先级添加/更改/删除条件

为了更好地描述问题陈述,下面是我的两个表(示例键列),它们的结构如下

表1:-->此表包含提交的每个索赔的索赔相关信息

CLAIM_DOCUMENT   
--------------
(
HDR_SID NUMBER,
PRVDR_NPI   NUMBER,
INV_TYPE    VARCHAR2(4),
SPLTY       VARCHAR2(100),
PRCDR_CODE  VARCHAR2(100),
MDFR_CODE   VARCHAR2(10),
DIAG_CODE   VARCHAR2(100) )
表2:-->这是保存提供程序速率的配置表

PROVIDER_RATE  
-------------
( PRVDR_SID     NUMBER,
PRVDR_NPI       NUMBER,
SPLTY           VARCHAR2(100),
SUB_SPLTY       VARCHAR2(100),
PRCDR_CODE      VARCHAR2(100),
MDFR_CODE   VARCHAR2(10) 
RATE_VALUE      NUMBER(20,6)
RATE_TYPE       VARCHAR2(10)
);
目标是从提供者费率表中确定适用的费率值。 为了确定供应商费率,我们将索赔时提交的属性(即PRVDR\U NPI、PRCDR\U代码、MDFR\U代码)与提交给供应商费率的属性进行匹配,以找到费率值

索赔中的所有属性都可能与提供者费率不匹配,因此我们添加/更改/删除“WHERE”条件,直到从提供者费率表中找到费率值

例如,在第1遍中,业务规则说匹配所有可能的值,因此我编写SQL语句如下:

SELECT RATE_VALUE, RATE_TYPE into v_rate_value, v_rate_type 
FROM CLAIM_DOCUMENT cd, PROVIDER_RATE pr
WHERE cd.hdr_sid = p_hdr_sid      -- p_hdr_sid is passed as parameter to procedure for 1 claim
AND cd.PRVDR_NPI = pr.PRVDR_NPI    -- PRVDR_NPI is key column to match between 2 tables
----all optional where clause to form here based on busienss rules priority --
AND cd.PRCDR_CODE = pr.PRCDR_CODE          -- optional WHERE clause 1
AND cd.MDFR_CODE = pr.MDFR_CODE          -- optional WHERE clause 2
AND cd.SPLTY = pr.SPLTY               -- optional WHERE clause 3

--IF rate value is NOT found using all WHERE clause above, the next rule priority 
--is to REMOVE SPLTY and check
    IF v_rate_value IS NULL THEN
        SELECT RATE_VALUE, RATE_TYPE into v_rate_value, v_rate_type 
        FROM CLAIM_DOCUMENT cd, PROVIDER_RATE pr
        WHERE cd.hdr_sid = p_hdr_sid      -- p_hdr_sid is passed as parameter to procedure for 1 claim
        AND cd.PRVDR_NPI = pr.PRVDR_NPI    -- PRVDR_NPI is key column to match between 2 tables
        ----all optional where clause to form here based on busienss rules priority --
        AND cd.PRCDR_CODE = pr.PRCDR_CODE          -- optional WHERE clause 1
        AND cd.MDFR_CODE = pr.MDFR_CODE          -- optional WHERE clause 2
    END IF;
--IF rate value is NOT found using WHERE clause above, 
--the next rule priority is to REMOVE MDFR_CODE and check
        IF v_rate_value IS NULL THEN
            SELECT RATE_VALUE, RATE_TYPE into v_rate_value, v_rate_type 
            FROM CLAIM_DOCUMENT cd, PROVIDER_RATE pr
            WHERE cd.hdr_sid = p_hdr_sid      -- p_hdr_sid is passed as parameter to procedure for 1 claim
            AND cd.PRVDR_NPI = pr.PRVDR_NPI    -- PRVDR_NPI is key column to match between 2 tables
            ----all optional where clause to form here based on busienss rules priority --
            AND cd.PRCDR_CODE = pr.PRCDR_CODE          -- optional WHERE clause 1
        END IF;
我的问题: 有没有办法通过读取表中配置的业务规则,更重要的是执行
没有硬解析的动态形成的SQL语句?

可以有条件地像这样打开/关闭条件:

AND (cd.PRCDR_CODE = pr.PRCDR_CODE OR l_prcdr_code_flag='off')  -- optional WHERE clause 1
AND (cd.MDFR_CODE = pr.MDFR_CODE OR l_mdfr_code_flag='off')  -- optional WHERE clause 2
AND (cd.SPLTY = pr.SPLTY OR l_splty_flag='off')  -- optional WHERE clause 3
在代码的其余部分中,您所要做的就是处理“标志”,即在开始时将所有
l_*\u标志
变量设置为
'on'
,然后在运行时将其关闭(将其设置为
'off'
)。 这样您就不会更改SQL,因此不需要进行硬解析。 为查询创建游标变量也是一个好主意,以避免重复代码。

您可以尝试以下方法:

SELECT RATE_VALUE, RATE_TYPE, 
       CASE
         WHEN
           cd.PRCDR_CODE = pr.PRCDR_CODE          -- optional WHERE clause 1
           AND cd.MDFR_CODE = pr.MDFR_CODE          -- optional WHERE clause 2
           AND cd.SPLTY = pr.SPLTY               -- optional WHERE clause 3
         THEN 1
         WHEN
           cd.PRCDR_CODE = pr.PRCDR_CODE          -- optional WHERE clause 1
           AND cd.MDFR_CODE = pr.MDFR_CODE          -- optional WHERE clause 2
         THEN 2
         WHEN
           cd.PRCDR_CODE = pr.PRCDR_CODE          -- optional WHERE clause 1
         THEN 3
       END matching_factor
  FROM CLAIM_DOCUMENT cd, PROVIDER_RATE pr
 WHERE cd.hdr_sid = p_hdr_sid      -- p_hdr_sid is passed as parameter to procedure for 1 claim
   AND cd.PRVDR_NPI = pr.PRVDR_NPI
 ORDER BY 3;
这样,您将捕获满足连接条件的所有记录(
cd.PRVDR\u NPI=pr.PRVDR\u NPI
),并且
matching\u factor
将告诉您哪些附加条件也满足(
1
=>所有3个可选子句都满足,
3
=>只有PRCDR\u code子句满足)。 根据此匹配因子对结果集排序,第一行应该是最佳匹配。
这次我做对了吗?

当然,只要阅读业务规则,把它们放在
变量varchar2(100)
执行立即变量中
查询会有多少变化?如果只有3个,那么硬解析就不重要了。我不想使用EXECUTE IMMEDIATE,因为这个过程是最常用的,我相信这会造成性能问题。可能会有很多变化,所以我想让它更具可配置性和动态性,但不会以牺牲性能为代价只是一个提示:使用
SELECT。。。如果查询返回零行或多行,INTO…
将引发异常,因此这种精确的查询语法将不适用于您。首先,谢谢。不确定是否正确,所以我想问一下这个场景。如果我不需要考虑每个业务需求,那么FLAG将如何帮助您,例如,您可以假设我必须只执行以下操作吗?(cd.PRCDR_CODE=pr.PRCDR_CODE或l_PRCDR_CODE_flag='off')--可选,其中第1条为}感谢GoranM的支持。您的解决方案看起来确实更好。当我们必须了解设计和实施过程中可能出现的所有排列时,您的解决方案工作得很好。我更感兴趣的是,如果出现新的更改请求,其中说检查PRVDR\u NPI和SPLY,这应该是最高优先级。我们可以接受吗在不更改代码的情况下修改此更改请求?如果需要更多详细信息,请告诉我。再次感谢