我在Oracle
中有一个函数,用于检查第一个日期是否包含第二个日期。它没有问题,因为如果[a, b]
[x, y]
包含x => a and y <= b and x <= y
。适用于定义的start/end date 1
和start/end date 2
。但现在我想修改它。如果给定'starting'
或'ending'
日期中的任何一个NULL
,则应将其视为+-infinite
。
这是一个代码:
FUNCTION CONTAINS(p_START_DATE_1 DATE, p_END_DATE_1 DATE,
p_START_DATE_2 DATE, p_END_DATE_2 DATE) RETURN VARCHAR2 AS
lv_RESULT VARCHAR2(1);
BEGIN
lv_RESULT := 'N';
IF (/* milions of conditions here */) THEN
lv_RESULT := 'Y';
END IF;
RETURN lv_RESULT;
END CONTAINS;
例如:假设p_START_DATE_1
为NULL
。在这种情况下代码:
SELECT MY_PACKAGE_SQL.CONTAINS(
NULL,
TO_DATE('01/12/2014', 'DD/MM/YYYY'),
TO_DATE('01/02/2012', 'DD/MM/YYYY'),
TO_DATE('01/05/2012', 'DD/MM/YYYY'))
FROM DUAL;
...应该返回Y
,因为第一个日期范围是(-infinite, 01/12/2014]
,它包含[01/02/2012, 01/05/2012]
。
现在我的问题......我知道我可以使用额外的"IFs"
来检查NULLs
。我必须使用"IFs"
(老板命令我这样做:S)。您是否知道如何仅使用"IFs"
以“智能”方式进行操作?
答案 0 :(得分:2)
使用可用例程处理NULL的一种方法是:
FUNCTION CONTAINS(a DATE, b DATE, -- does interval [a, b] contain [x, y]?
x DATE, y DATE)
RETURN VARCHAR2
AS
lv_RESULT VARCHAR2(1);
dtPositiveInfinity DATE := TO_DATE('31-DEC-9999 23:59:59',
'DD-MON-YYYY HH24:MI:SS');
dtNegativeInfinity DATE := TO_DATE('01-JAN-4712 BC 00:00:00',
'DD-MON-YYYY BC HH24:MI:SS');
BEGIN
lv_RESULT := 'N';
IF NVL(x, dtPositiveInfinity) >= NVL(a, dtNegativeInfinity) AND
NVL(y, dtNegativeInfinity) <= NVL(b, dtPositiveInfinity) AND
NVL(x, dtNegativeInfinity) <= NVL(y, dtPositiveInfinity)
THEN
lv_RESULT := 'Y';
END IF;
RETURN lv_RESULT;
END CONTAINS;
但是,你说你不能使用COALESCE,因此我推断你也不能使用NVL,在这种情况下可能会有以下情况:
FUNCTION CONTAINS(a DATE, b DATE, -- does interval [a, b] contain [x, y]?
x DATE, y DATE)
RETURN VARCHAR2
AS
lv_RESULT VARCHAR2(1);
dtPositiveInfinity DATE := TO_DATE('31-DEC-9999 23:59:59',
'DD-MON-YYYY HH24:MI:SS');
dtNegativeInfinity DATE := TO_DATE('01-JAN-4712 BC 00:00:00',
'DD-MON-YYYY BC HH24:MI:SS');
aOrNegativeInfinity DATE := a;
bOrPositiveInfinity DATE := b;
xOrPositiveInfinity DATE := x;
yOrPositiveInfinity DATE := y;
xOrNegativeInfinity DATE := x;
yOrNegativeInfinity DATE := y;
BEGIN
lv_RESULT := 'N';
IF a IS NULL THEN
aOrNegativeInfinity := dtNegativeInfinity;
END IF;
IF b IS NULL THEN
bOrPositiveInfinity := dtPositiveInfinity;
END IF;
IF x IS NULL THEN
xOrPositiveInfinity := dtPositiveInfinity;
xOrNegativeInfinity := dtNegativeInfinity;
END IF;
IF y IS NULL THEN
yOrPositiveInfinity := dtPositiveInfinity;
yOrNegativeInfinity := dtNegativeInfinity;
END IF;
IF xOrPositiveInfinity >= aOrNegativeInfinity AND
yOrNegativeInfinity <= bOrPositiveInfinity AND
xOrNegativeInfinity <= yOrPositiveInfinity
THEN
lv_RESULT := 'Y';
END IF;
RETURN lv_RESULT;
END CONTAINS;
如果使用多个IF语句存在问题,可能会接受以下内容:
FUNCTION CONTAINS(a DATE, b DATE, -- does interval [a, b] contain [x, y]?
x DATE, y DATE)
RETURN VARCHAR2
AS
lv_RESULT VARCHAR2(1);
dtPositiveInfinity DATE := TO_DATE('31-DEC-9999 23:59:59',
'DD-MON-YYYY HH24:MI:SS');
dtNegativeInfinity DATE := TO_DATE('01-JAN-4712 BC 00:00:00',
'DD-MON-YYYY BC HH24:MI:SS');
BEGIN
lv_RESULT := 'N';
IF CASE x WHEN NULL THEN dtPositiveInfinity ELSE x END >=
CASE a WHEN NULL THEN dtNegativeInfinity ELSE a END AND
CASE y WHEN NULL THEN dtNegativeInfinity ELSE y END <=
CASE b WHEN NULL THEN dtPositiveInfinity ELSE b END AND
CASE x WHEN NULL THEN dtNegativeInfinity ELSE x END <=
CASE y WHEN NULL THEN dtPositiveInfinity ELSE y END
THEN
lv_RESULT := 'Y';
END IF;
RETURN lv_RESULT;
END CONTAINS;
未在动物身上进行测试 - 您将成为第一个!
分享并享受。
答案 1 :(得分:1)
这是逻辑,表示为case
语句:
select (case when (p_START_DATE_1 is null or
p_START_DATE_1 >= p_START_DATE_2 or
p_START_DATE_1 is null and p_START_DATE_2 is null
) and
(p_END_DATE_1 <= p_END_DATE_2) and
(p_START_DATE_1 <= p_END_DATE_1 or p_START_DATE_1 is null
then 'Y'
else 'N'
end)
您也可以使用coalesce()
更轻松地表达这一点:
select (case when coalesce(p.START_DATE_1, to_date('1900-01-01', 'YYYY-MM-DD')) > p_START_DATE_2 and
(p_END_DATE_1 <= p_END_DATE_2) and
coalesce(p.START_DATE_1, to_date('1900-01-01', 'YYYY-MM-DD')) <= p_END_DATE_2
then 'Y'
else 'N'
end)
如果您希望其他列的其他逻辑为NULL
(并且您有可用于NULL
值的极端日期),则此方法会更容易。