【问题标题】:Boolean return value of some function inside SELECTSELECT 中某个函数的布尔返回值
【发布时间】:2026-01-13 05:30:02
【问题描述】:

我正在使用 PL/SQL 编写一个包。

这是我的规格:

TYPE outrec IS RECORD(
    tw_m_id                         NUMBER,
    tw_m_dealer_id                  NUMBER,
    tw_number                       NUMBER,
    check_uid                       NUMBER);
  TYPE outrecset IS TABLE OF outrec;

  FUNCTION report
  (
    p_watermark           IN NUMBER,
    p_param               IN NUMBER,
    p_index               IN NUMBER
  ) RETURN outrecset
    PIPELINED;

这是我的身体:

FUNCTION func
  (
    p_watermark           => p_watermark,
    p_param               => p_param,
    p_index               => p_index
  )
  
   RETURN outrecset
    PIPELINED IS
    temp outrec;
  
  BEGIN
    before_report(p_watermark           => p_watermark,
                  p_param               => p_param,
                  p_index               => p_index);
  
    FOR c_rec IN (SELECT tw_m_id,
                         tw_m_dealer_id,
                         tw_number,
                         package_name.somefunction(tw_number) AS check_uid

                    FROM table1
                    JOIN table2 rk ON id1 = rk.id2
                    WHERE 1 = 1
                    AND id1 = rk.id2
                    AND id1 = p_param)
    
    LOOP
      temp.tw_m_tw_rechnungskopf_id       := c_rec.tw_m_tw_rechnungskopf_id;
      temp.tw_m_haendler_id_rechnung      := c_rec.tw_m_haendler_id_rechnung;
      temp.check_uid                      := c_rec.check_uid;
      PIPE ROW(temp);
    END LOOP;
  END;

我正在尝试从 package_name.somefunction(tw_number) AS check_uid 中获取价值。问题是 somefunction 返回 BOOLEAN 值。 当我将 check_uid 设置为 BOOLEAN 时,我得到 Error: PLS-00382: expression is of wrong type 因为当然 SQL 不支持 BOOLEAN。我试过了:

CASE 
WHEN package_name.somefunction(tw_number) THEN true 
else false
END as check_uid

在 SELECT 内然后我得到错误:PL/SQL: ORA-00920: 无效的关系运算符。

谁能告诉我如何做到这一点 PL/SQL 不是我最擅长的方面:(

  • 编辑:我无法更改某些函数以返回示例 varchar2 它需要保持原样

【问题讨论】:

    标签: sql oracle plsql boolean plsql-package


    【解决方案1】:

    编写一个简单的包装函数,将 PL/SQL BOOLEAN 转换为在 SQL 中有效且记录类型所期望的 NUMBER 数据类型,并且您可以将函数调用移到 SQL 之外。

    CREATE FUNCTION MAP_BOOLEAN( truthy IN BOOLEAN ) RETURN NUMBER DETERMINISTIC
    IS
    BEGIN
      RETURN CASE truthy
             WHEN TRUE  THEN 1
             WHEN FALSE THEN 0
             ELSE NULL
             END;
    END map_boolean;
    /
    

    所以你的规范是:

    CREATE PACKAGE package_name IS
      TYPE outrec IS RECORD(
        tw_m_id        NUMBER,
        tw_m_dealer_id NUMBER,
        tw_number      NUMBER,
        check_uid      NUMBER
      );
    
      TYPE outrecset IS TABLE OF outrec;
    
      -- Note: This may be in another package but is here for convenience.
      FUNCTION somefunction(value IN NUMBER) RETURN BOOLEAN;
    
      FUNCTION report
      (
        p_watermark IN NUMBER,
        p_param     IN NUMBER,
        p_index     IN NUMBER
      ) RETURN outrecset PIPELINED;
    END;
    /
    

    相应的正文将是:

    CREATE PACKAGE BODY package_name IS
      FUNCTION somefunction(value IN NUMBER) RETURN BOOLEAN
      IS
      BEGIN
        RETURN TRUE;
      END;
    
      PROCEDURE before_report(
        p_watermark IN NUMBER,
        p_param     IN NUMBER,
        p_index     IN NUMBER
      )
      IS
      BEGIN
        NULL;
      END;
    
    
      FUNCTION report(
        p_watermark IN NUMBER,
        p_param     IN NUMBER,
        p_index     IN NUMBER
      ) RETURN outrecset PIPELINED
      IS
        temp outrec;
      BEGIN
        before_report(
          p_watermark => p_watermark,
          p_param     => p_param,
          p_index     => p_index
        );
    
        FOR c_rec IN (
          SELECT tw_m_id,
                 tw_m_dealer_id,
                 tw_number
          FROM   table1
                 JOIN table2 rk ON id1 = rk.id2
          WHERE  id1 = p_param
        )
        LOOP
          temp.tw_m_id        := c_rec.tw_m_id;
          temp.tw_m_dealer_id := c_rec.tw_m_dealer_id;
          temp.check_uid      := MAP_BOOLEAN(
                                   PACKAGE_NAME.SOMEFUNCTION( c_rec.tw_number )
                                 );
          PIPE ROW(temp);
        END LOOP;
      END;
    END;
    /
    

    (注意:您还需要更新游标循环,因为您选择的值与记录的字段不匹配。)

    db小提琴here

    【讨论】:

    • 非常感谢这解决了我的问题:D
    【解决方案2】:

    通常你会在你的包中创建一个返回 1/0 或 Y/N 的重载函数。但由于您无权访问该包,您可以在 sql 查询中使用内联函数为您执行此操作。

    create or replace function func (parameter_i VARCHAR2) RETURN BOOLEAN
    AS
    BEGIN
      return true;
    END;
    /
    
    WITH
      FUNCTION func_yn(parameter_i VARCHAR2)
      RETURN NUMBER
      IS
        l_return_value BOOLEAN;
      BEGIN
        l_return_value :=func(parameter_i => parameter_i);
        RETURN CASE l_return_value WHEN TRUE THEN 1 WHEN FALSE THEN 0 END;
      END func_yn;
    SELECT 
      func_yn('test')
    FROM dual;
    

    【讨论】: