【问题标题】:How to use BOOLEAN type in SELECT statement如何在 SELECT 语句中使用 BOOLEAN 类型
【发布时间】:2018-06-01 13:50:17
【问题描述】:

我有一个参数为 BOOLEAN 的 PL/SQL 函数:

function get_something(name in varchar2, ignore_notfound in boolean);

此功能是第三方工具的一部分,我无法更改。

我想在这样的 SELECT 语句中使用这个函数:

 select get_something('NAME', TRUE) from dual;

这不起作用,我得到了这个异常:

ORA-00904:“TRUE”:标识符无效

据我了解,关键字TRUE 无法识别。

我怎样才能做到这一点?

【问题讨论】:

  • 我为 Oracle 感到尴尬,您甚至无法在 SQL 语句中与从 PL/SQL 块返回的布尔值进行比较。您甚至不能将这样的函数包装在 CASE 语句中。唯一明智的答案是将数据库升级到 PostgreSQL,它可以很好地处理 SQL 语句中的布尔值。
  • 这并不完全正确。使用内置的 sys.diutil.bool_to_int 将 BOOLEAN 转换为 INTEGER 0 或 1。在存储过程中,使用 BOOLEAN 变量没有问题,但这并不是这里真正关心的问题......

标签: sql oracle plsql oracle10g ora-00904


【解决方案1】:

PL/SQL 抱怨 TRUE 不是有效的标识符或变量。设置一个局部变量,将其设置为 TRUE,并将其传递给 get_something 函数。

【讨论】:

  • 不,Oracle SQL 根本无法处理布尔值:-(
  • 另外,我想在视图定义中使用这个函数,而不是在脚本中。
  • @Ula, Tony:那我想包装函数是最合适的方式。
  • @a_horse_with_no_name 我不确定你的意思是什么。是的,当然 PL/SQL 支持 Boolean 类型——问题表明了这一点。但是不,SQL 没有。因此“SQL 根本无法处理布尔值。”
  • @a_horse_with_no_name 呃。不,不是吗?!
【解决方案2】:

你可以像这样构建一个包装函数:

function get_something(name in varchar2,
                   ignore_notfound in varchar2) return varchar2
is
begin
    return get_something (name, (upper(ignore_notfound) = 'TRUE') );
end;

然后调用:

select get_something('NAME', 'TRUE') from dual;

ignore_notfound 在您的版本中的有效值由您决定,我假设“TRUE”表示 TRUE,其他任何值表示 FALSE。

【讨论】:

  • 来oracle,这是一个非常愚蠢的限制
  • 我很好奇 Oracle 如何在技术上证明这一点。
  • 事实上,Ask Tom (oracles oracle) 在他的回答中居高临下地说 char(1) ('Y'/'N') “具有相同的目的”。 asktom.oracle.com/pls/asktom/…
  • F_IS_YES - 可从任何 Oracle SQL 用法调用:SELECT * FROM WHATEVER WHEN F_IS_YES(SOMECOL)=1;太局限了。如何使用内置?创建或替换函数 F_IS_YES(pVal IN VARCHAR2) return INTEGER is begin return(sys.diutil.bool_to_int( kdot_blp_util.f_is_yes(pVal)) );其他人返回 0 时的例外情况; -- 拒绝接受您的请求 - 意味着没有结束 F_IS_YES;我尝试了以下 VARCHAR2 值,它们都返回了预期的 0 或 1:YES NO Y N T F y n true false
【解决方案3】:

来自documentation

您不能将值 TRUEFALSE 插入到数据库列中。您不能将列值选择或提取到BOOLEAN 变量中。从SQL 查询调用的函数不能采用任何BOOLEAN 参数。也不能内置SQLTO_CHAR等函数;要在输出中表示BOOLEAN 值,您必须使用IF-THENCASE 构造将BOOLEAN 值转换为其他类型,例如01'Y''N'、@ 987654337@或'false'等。

您需要创建一个采用 SQL 数据类型的包装函数并使用它。

【讨论】:

    【解决方案4】:

    BOOLEAN 数据类型是 PL/SQL 数据 类型。 Oracle 不提供 等效的 SQL 数据类型 (...),您可以 创建一个包装函数,它映射一个 SQL 类型转为 BOOLEAN 类型。

    检查这个:http://forums.datadirect.com/ddforums/thread.jspa?threadID=1771&tstart=0&messageID=5284

    【讨论】:

      【解决方案5】:

      如何使用计算结果为 TRUE(或 FALSE)的表达式?

      select get_something('NAME', 1 = 1) from dual
      

      【讨论】:

        【解决方案6】:

        在您的数据库中编译它并开始在您的查询中使用布尔语句。

        注意:函数 get 是一个 varchar2 参数,因此请务必在语句中包含任何“字符串”。它将返回 1 为真,0 为假;

        select bool('''abc''<''bfg''') from dual;
        
        CREATE OR REPLACE function bool(p_str in varchar2) return varchar2 
         is
         begin
        
         execute immediate ' begin if '||P_str||' then
                  :v_res :=  1;
               else
                  :v_res :=  0;
               end if; end;' using out v_res;
        
               return v_res;
        
         exception 
          when others then 
            return '"'||p_str||'" is not a boolean expr.';
         end;
        /
        

        【讨论】:

        • 这个特殊的解决方案似乎是一个非常糟糕的选择。为什么要支付让执行立即加载和触发的开销?我想我可以理解对某种通用布尔评估器的需求,但不是在 SQL 语句中。
        【解决方案7】:

        您绝对可以从 SELECT 查询中获取布尔值,只是不能使用布尔数据类型。

        您可以用 1/0 表示布尔值。

        CASE WHEN (10 > 0) THEN 1  ELSE 0 END (It can be used in SELECT QUERY)
        
        SELECT CASE WHEN (10 > 0) THEN 1  ELSE 0 END AS MY_BOOLEAN_COLUMN
          FROM DUAL
        

        返回,1(在 Hibernate/Mybatis/etc 中 1 为真)。否则,您可以从 SELECT 中获取可打印的布尔值。

        SELECT CASE WHEN (10 > 0) THEN 'true' ELSE 'false' END AS MY_BOOLEAN_COLUMN
         FROM DUAL
        

        这将返回字符串'true'

        【讨论】:

        • 虽然与问题完全无关。问题不是“我如何使用数字而不是布尔值”。
        【解决方案8】:
        select get_something('NAME', sys.diutil.int_to_bool(1)) from dual;
        

        【讨论】:

        • 产生 "ORA-00902 invalid datatype"
        【解决方案9】:

        简单地说,这个问题的答案是:不要将 BOOLEAN 与 Oracle 一起使用——PL/SQL 是愚蠢的,而且它不起作用。使用另一种数据类型来运行您的流程。

        使用 Oracle 数据源的 SSRS 报表开发人员须知:您可以使用 BOOLEAN 参数,但要注意如何实现。 Oracle PL/SQL 不能很好地使用 BOOLEAN,但如果数据位于数据集中,您可以在 Tablix 过滤器中使用 BOOLEAN 值。这真的让我大吃一惊,因为我在 Oracle 数据源中使用了 BOOLEAN 参数。但在那种情况下,我过滤的是 Tablix 数据,而不是 SQL 查询。

        如果数据不在您的 SSRS 数据集字段中,您可以使用 INTEGER 参数重写 SQL:

        __

        <ReportParameter Name="paramPickupOrders">
          <DataType>Integer</DataType>
          <DefaultValue>
            <Values>
              <Value>0</Value>
            </Values>
          </DefaultValue>
          <Prompt>Pickup orders?</Prompt>
          <ValidValues>
            <ParameterValues>
              <ParameterValue>
                <Value>0</Value>
                <Label>NO</Label>
              </ParameterValue>
              <ParameterValue>
                <Value>1</Value>
                <Label>YES</Label>
              </ParameterValue>
            </ParameterValues>
          </ValidValues>
        </ReportParameter>
        
        ...
        
        <Query>
        <DataSourceName>Gmenu</DataSourceName>
        <QueryParameters>
          <QueryParameter Name=":paramPickupOrders">
            <Value>=Parameters!paramPickupOrders.Value</Value>
          </QueryParameter>
        <CommandText>
            where 
                (:paramPickupOrders = 0 AND ordh.PICKUP_FLAG = 'N'
                OR :paramPickupOrders = 1 AND ordh.PICKUP_FLAG = 'Y' )
        

        如果数据在您的 SSRS 数据集字段中,您可以使用带有 BOOLEAN 参数的 tablix 过滤器:

        __

        </ReportParameter>
        <ReportParameter Name="paramFilterOrdersWithNoLoad">
          <DataType>Boolean</DataType>
          <DefaultValue>
            <Values>
              <Value>false</Value>
            </Values>
          </DefaultValue>
          <Prompt>Only orders with no load?</Prompt>
        </ReportParameter>
        
        ...
        
        <Tablix Name="tablix_dsMyData">
        <Filters>
          <Filter>
            <FilterExpression>
                =(Parameters!paramFilterOrdersWithNoLoad.Value=false) 
                or (Parameters!paramFilterOrdersWithNoLoad.Value=true and Fields!LOADNUMBER.Value=0)
            </FilterExpression>
            <Operator>Equal</Operator>
            <FilterValues>
              <FilterValue DataType="Boolean">=true</FilterValue>
            </FilterValues>
          </Filter>
        </Filters>
        

        【讨论】:

          【解决方案10】:

          在 Oracle 12 中,您可以使用 WITH 子句来声明您的辅助函数。我假设你的get_something 函数返回varchar2

          with
            function get_something_(name varchar2, ignore_notfound number)
            return varchar2 
            is
            begin
              -- Actual function call here
              return get_something(name, not ignore_notfound = 0);
            end get_something_;
          
            -- Call auxiliary function instead of actual function
          select get_something_('NAME', 1) from dual;
          

          当然,您也可以将辅助函数存储在架构as shown in this answer 的某个位置,但是通过使用WITH,您没有任何外部依赖项来运行此查询。 I've blogged about this technique more in detail here.

          【讨论】:

            猜你喜欢
            • 2011-07-07
            • 2015-10-20
            • 1970-01-01
            • 2015-05-28
            • 1970-01-01
            • 2010-10-11
            • 2015-09-17
            • 1970-01-01
            相关资源
            最近更新 更多