【问题标题】:Using a Function inside a Select ORACLE SQL [duplicate]在 Select ORACLE SQL 中使用函数 [重复]
【发布时间】:2021-03-23 04:28:15
【问题描述】:

我有这个功能:

CREATE FUNCTION ISROOMAVAILABLE(P_ID_ROOM INT, P_DATE DATE) RETURN BOOLEAN
    IS
    V_COUNT INT;
BEGIN
    SELECT count(*)
    INTO V_COUNT
    FROM CHECKIN A
             LEFT JOIN CHECKOUT B ON (A.ID_RESERVATION = B.ID_RESERVATION)
    WHERE A.ID_ROOM = P_ID_ROOM
      AND ((A.DATE >= trunc(P_DATE) AND B.DATE IS NULL)
        OR
           (A.DATE <= trunc(P_DATE) AND B.DATE >= trunc(P_DATE)));
    RETURN (V_COUNT > 0);
END;

如果房间(由其 ID 标识)在特定日期可用,则返回 true。

我想使用上面的函数作为我选择的决定因素来检查多个参数:

    SELECT Q.ID, COUNT(R.DATE_OUT - R.DATE_IN) AS DAYS
    FROM QUARTO Q
             JOIN CHECKIN CI ON Q.ID = CI.ID_ROOM
             JOIN RESERVATION R ON CI.ID_RESERVATION = R.ID
    WHERE (EXTRACT(YEAR FROM R.DATE_IN) = EXTRACT(YEAR FROM SYSDATE))
      AND (ISROOMAVAILABLE(Q.ID, SYSDATE))
    GROUP BY Q.ID
    ORDER BY DAYS;

我在函数中使用 sysdate,因为我仍然缺少数据库中的一些数据,但我得到的错误仍然是“关系运算符无效”。

有什么方法可以使用我在“WHERE”子句中的功能?

请原谅我的葡萄牙语翻译不好,我不知道英文的确切术语。

【问题讨论】:

  • @OldProgrammer - 这不是完全相同的问题。您指向的线程是关于一个更难的问题,该函数需要布尔输入。在这个线程中,问题更简单——只有返回数据类型是一个问题,而且更容易解决。 SO上有很多其他类似的问题,我会找到一个并关闭这个帖子。

标签: sql oracle plsql where-clause sql-function


【解决方案1】:

我认为 Oracle 无法评估 SQL 查询的 WHERE 子句中的 PL/SQL 布尔值。

最简单的方法是修改函数,使其返回可以评估的内容。例如,我们可以返回 1 为真,0 为假:

CREATE FUNCTION ISROOMAVAILABLE(P_ID_ROOM INT, P_DATE DATE) RETURN INT
    IS
    V_COUNT INT;
BEGIN
    SELECT count(*)
    INTO V_COUNT
    FROM CHECKIN A
             LEFT JOIN CHECKOUT B ON (A.ID_RESERVATION = B.ID_RESERVATION)
    WHERE A.ID_ROOM = P_ID_ROOM
      AND ((A.DATE >= trunc(P_DATE) AND B.DATE IS NULL)
        OR
           (A.DATE <= trunc(P_DATE) AND B.DATE >= trunc(P_DATE)));
    RETURN LEAST(V_COUNT, 1);
END;

然后:

WHERE ...
  AND ISROOMAVAILABLE(Q.ID, SYSDATE) = 1

如果您无法修改函数,则需要将其包装在另一个函数中,该函数返回可以在 SQL 中计算的数据类型,并调用包装函数而不是原始函数。

与您的查询无关的注释:

  • EXTRACT(YEAR FROM R.DATE_IN) = EXTRACT(YEAR FROM SYSDATE) 不是最理想的。这将通过直接过滤更有效地表达:
    R.DATE_IN >= TRUNC(SYSDATE, 'YEAR') 
AND R.DATE_IN < ADD_MONTHS(TRUNC(SYSDATE, 'YEAR'), 12)
  • 我想知道COUNT(R.DATE_OUT - R.DATE_IN) 是否符合您的要求。它的作用是计算两个日期都不是NULL 的所有行。也许您的意思是:SUM(R.DATE_OUT - R.DATE_IN)

【讨论】:

  • 布尔值是合适的数据类型;问题是 Oracle SQL 不支持它。更常见的解决方法(而不是按照您的建议返回计数)是返回 0 表示假,1 表示真(返回数据类型 NUMBER),或者可能返回字符串,如 'Y'/'N' 或 'true'/'false '
  • @mathguy:这就是我的意思......我调整了措辞。我还将返回值更改为 0/1(尽管计数在这里可以很好地完成工作,WHERE 子句中有一个不等式条件)。
  • 感谢您提供有关日期的提示。我按照您的建议通过更改函数的返回解决了这个问题。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2014-02-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多