如何在SELECT语句中使用BOOLEAN类型

67

我有一个带有 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未被识别。

我该如何使其正常运行?


2
我为Oracle感到尴尬,因为你甚至无法在SQL语句中使用从PL/SQL块返回的布尔值进行比较。你甚至不能将这样的函数包装在"CASE"语句中。唯一明智的解决方案是升级你的数据库到PostgreSQL,它可以完美地处理SQL语句中的布尔值。 - cartbeforehorse
这并不完全正确。使用内置的sys.diutil.bool_to_int将BOOLEAN转换为INTEGER 0或1。在存储过程中,使用BOOLEAN变量没有问题,但这并不是关注的问题... - Allen
PostgreSQL在列中具有布尔数据类型。在这方面,它比Oracle更现代化。此外,它还具有无限字符串的TEXT数据类型... - Roland
11个回答

55

你可以通过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等中,1代表true)。否则,您可以从SELECT中获取可打印的布尔值。

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

这将返回字符串'true'


6
虽然与问题完全无关,但这个问题并不是“如何使用数字代替布尔值”。 - cartbeforehorse

32

你可以创建一个类似这样的包装函数:

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。


30
来吧,Oracle,这个限制真的很愚蠢。 - craigrs84
8
我很好奇 Oracle 在技术上是如何进行辩解的。 - srage
4
事实上,Ask Tom(Oracle的Oracle)在他的回答中有点居高临下,说char(1)('Y'/'N')“具有相同的目的”。 - Sonic Soul
F_IS_YES - 可从任何Oracle SQL中调用用法:SELECT * FROM WHATEVER WHEN F_IS_YES(SOMECOL)=1; 太过限制。使用内置的怎么样? 创建或替换函数F_IS_YES(pVal IN VARCHAR2)返回INTEGER是开始 返回(sys.diutil.bool_to_int(kdot_blp_util.f_is_yes(pVal))); EXCEPTION WHEN OTHERS THEN 返回0; - 不愿意满足您的请求 - 意味着不 end F_IS_YES;我尝试了以下VARCHAR2值,并且它们都返回了预期的0或1: YES NO Y N T F y n true false - Allen

27

文档中得知:

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

你需要创建一个包装函数来处理 SQL 数据类型。


6

3
select get_something('NAME', sys.diutil.int_to_bool(1)) from dual;

3
这会产生“ORA-00902无效数据类型”的错误。 - Lukas Eder

2

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

注意:该函数接收一个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;
/

2
这个特定的解决方案似乎是一个非常糟糕的选择。为什么要支付获取execute immediate并在此处加载和触发的开销呢?我想我可以理解需要某种通用布尔表达式求值器,但不应该在SQL语句中实现。 - Allen

2
在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;

当然,你也可以像这个回答中所示,在模式中存储您的辅助函数,但是使用WITH,您不需要任何外部依赖项来运行此查询。我在这里更详细地介绍了这种技术。请注意保留HTML标签。

2

Oracle数据库23c已经在SQL中添加了布尔数据类型。因此,您现在可以在查询中调用返回布尔值的PL/SQL函数以及其他布尔表达式:

create or replace function gt_zero ( p int ) 
  return boolean as
begin
  return p > 0;
end;
/

select 
  gt_zero ( -1 ) minus_one, 
  gt_zero ( 1 ) one, 
  0 > 0 zero;
  
MINUS_ONE   ONE         ZERO
----------- ----------- -----------
FALSE       TRUE        FALSE

0
简单来说,这个问题的答案是:不要在Oracle中使用BOOLEAN——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数据集字段中,您可以使用带有布尔参数的表格过滤器:

__

</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>

-3

你觉得使用一个能够评估为TRUE(或FALSE)的表达式如何?

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

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接