Oracle正在SQL中运行my函数,用于WHERE子句中过滤掉的数据

Oracle正在SQL中运行my函数,用于WHERE子句中过滤掉的数据,sql,oracle,oracle11g,Sql,Oracle,Oracle11g,我有一个Oracle SQL语句,它获取一些数据,并将其传递给一个函数,该函数返回一个值。如果收到的数据无效,该函数将引发应用程序错误 函数正在引发错误,因为它正在获取不应该包含的数据,即使该数据已在where子句中或通过隐式内部联接过滤掉 基本上,Oracle似乎是在过滤掉数据之前将数据传递给函数。我怎样才能防止这种情况 您可以在查询正在运行的函数下面看到注释。最后一个谓词和WHSE.WIDX=5632使此SQL返回0个结果,但是如果没有它,该值将传递给PAS.PAS\u MERCH\u PL

我有一个Oracle SQL语句,它获取一些数据,并将其传递给一个函数,该函数返回一个值。如果收到的数据无效,该函数将引发应用程序错误

函数正在引发错误,因为它正在获取不应该包含的数据,即使该数据已在where子句中或通过隐式内部联接过滤掉

基本上,Oracle似乎是在过滤掉数据之前将数据传递给函数。我怎样才能防止这种情况

您可以在查询正在运行的函数下面看到注释。最后一个谓词和WHSE.WIDX=5632使此SQL返回0个结果,但是如果没有它,该值将传递给PAS.PAS\u MERCH\u PLAN.GET\u WHSE\u CUST\u PRICE\u SCHEME函数

    SELECT
      DISTINCT WHSE.WIDX
    FROM
      AP21.STKAUD
    LEFT JOIN
      AP21.POZD
      ON POZD.POZDIDX = STKAUD.TRANIDX
    LEFT JOIN
      AP21.PORDD 
      ON PORDD.PORDDIDX = POZD.PORDDIDX
    LEFT JOIN 
      AP21.PORD
      ON PORD.PORDIDX = PORDD.PORDIDX
    INNER JOIN
      AP21.WHSE
      ON WHSE.WIDX = STKAUD.WHSIDX
   -- INNER JOIN
   --   AP21.REFCODE CURRENCY ON
   --   CURRENCY.RCIDX = PAS.PAS_MERCH_PLAN.GET_PRICE_SCHEME_CURRENCY(PAS.PAS_MERCH_PLAN.GET_WHSE_CUST_PRICE_SCHEME(WHSE.WIDX))
    INNER JOIN
      AP21.REFCODE WHSE_RC ON
      WHSE_RC.RCIDX = STKAUD.WHSIDX
    LEFT OUTER JOIN
    (
      SELECT
        BUSDIV,
        WHSEIDX
      FROM
        AP21.GIT_MERCH_PLANNING_CONFIG PLAN_CONF
      UNPIVOT (WHSEIDX FOR WAREHOUSE_CODE IN (WHSE1,WHSE2,WHSE3,WHSE4,WHSE5))
    ) RETAIL_WAREHOUSE ON
      RETAIL_WAREHOUSE.WHSEIDX = WHSE.WIDX
      AND RETAIL_WAREHOUSE.BUSDIV = WHSE.REF1
    WHERE
      (
        WHSE.TYPE = 'R'
        OR RETAIL_WAREHOUSE.WHSEIDX IS NOT NULL
      )
      AND
      (
        STKAUD.TRANTYPE = '231' --TRANSFER OUT
        OR STKAUD.TRANTYPE = '32125' --STOCK WRITEDOWN
        OR STKAUD.TRANTYPE = '32124' --DIRECT STOCK TRANSFER
        OR (STKAUD.TRANTYPE = '210' AND COLUMN1 = 0 AND NVL(PORD.ARMS_LENGTH_DIRECT,0) <> 1 ) --WAREHOUSE PURCHASE ORDER RECEIPTS excluding Intercompany
        OR (STKAUD.TRANTYPE = '104' AND COLUMN1 = 0) --WAREHOUSE PRODUCTION RECEIPTS
      )
      AND TRANDATE >= TRUNC(SYSDATE-1)
      AND TRANDATE < TRUNC(SYSDATE-1)+1
      AND WHSE.WIDX = 5632

我认为您无法控制Oracle在解决查询时的操作

当显示查询时,它会准备一个执行计划,并可能决定首先计算这些值,然后在最后进行筛选

也许,如果您修改了内部连接并在其中添加了该条件,那么它会在调用函数之前应用该过滤器

...
INNER JOIN
AP21.REFCODE CURRENCY ON
WHSE.WIDX = 5632 
AND
CURRENCY.RCIDX = PAS.PAS_MERCH_PLAN.GET_PRICE_SCHEME_CURRENCY(PAS.PAS_MERCH_PLAN.GET_WHSE_CUST_PRICE_SCHEME(WHSE.WIDX))
...

您可以使用CASE语句强制条件短路,例如,写入函数为_VALIDwidx

INNER JOIN
AP21.REFCODE CURRENCY ON
CURRENCY.RCIDX = 
    CASE WHEN IS_VALID(WHSE.WIDX) = 'Y' 
    THEN PAS.PAS_MERCH_PLAN.GET_PRICE_SCHEME_CURRENCY(PAS.PAS_MERCH_PLAN.GET_WHSE_CUST_PRICE_SCHEME(WHSE.WIDX))
    END

确保只对满足查询中其他条件的行调用该函数的一个好方法是将查询的其余部分放入子查询中,并在外部查询中调用该函数,例如:

SELECT q.WIDX
FROM   (your query) q
JOIN    AP21.REFCODE CURRENCY
ON      CURRENCY.RCIDX
  = PAS.PAS_MERCH_PLAN.GET_PRICE_SCHEME_CURRENCY(
      PAS.PAS_MERCH_PLAN.GET_WHSE_CUST_PRICE_SCHEME(q.WIDX))

我想情况就是这样,但是我希望有一种方法可以重新安排查询,或者可能是优化器提示。上述方法不起作用,因为谓词WHSE.WIDX=5632不是硬编码的,它只是为了解决这个问题。我可以修改函数以只返回NULL,但是我们希望它在合法情况下引发错误。即使没有硬编码,也不能动态地重复它?不幸的是,即使这种方法也不是100%可靠的。有关案例短路不能防止错误的示例,请参阅。