【问题标题】:Function with dates as params that can be NULL以日期为参数的函数,可以为 NULL
【发布时间】:2014-11-25 09:34:18
【问题描述】:

我正在尝试在 PostgreSQL 9.3.5 中实现一个以日期为参数的函数。
它应该涵盖以下所有条件并相应地返回结果。

select * from tablename
where sid is not null and dob >= '11-14-2014' order by dob;
-- Only Start Date

select * from tablename
where sid is not null and dob <= '11-21-2014' order by dob;
-- Only End Date

select * from tablename
where sid is not null and dob between '11-10-2014' and '11-21-2014' order by dob; 
-- Both Start and End Dates are Given

select * from tablename
where sid is not null and dob is null; 
-- Both Start and End Dates are Null

SQL Fiddle

但是我上面的 SQL Fiddle 没有按预期工作。

我想要一个通用的实现,这样如果明天我有更多的new Date Fields 到条件搜索中,那么我可以将它们添加到where condition 中,但不能添加到IF 语句的每一行中。

Updated SQL Fiddle

【问题讨论】:

  • 为什么需要单独的函数?您上述所有查询似乎都符合您的要求。一个单独的函数看起来有点太过分了,因为查询处理得很好并且更具可读性。
  • @DrColossos 我需要一个函数,因为我试图根据传递的参数(基于标准)获取详细信息,所以我想将它们变成一个函数,以便我可以使用该函数返回结果就像将它们用作单行查询时所做的那样。

标签: sql postgresql null date-range postgresql-9.3


【解决方案1】:

这可以简单得多

您可以将@Clodoaldo 目前接受的答案中的表达式简化为:

SELECT *
FROM   sampletest
WHERE  eid IS NOT NULL
AND   (_sd IS NULL AND _ed IS NULL OR
       _sd IS NULL AND dob <= _ed  OR
       _ed IS NULL AND dob >= _sd  OR
       dob BETWEEN _sd AND _ed);
  • 比较dob &gt;= _sd后,无需另外检查_sd is not null
    无论如何,表达式只能计算为 TRUE 和非空 _sd

但这些都不是必需的:

CREATE OR REPLACE FUNCTION test_dob_dates(_sd date, _ed date)
  RETURNS SETOF sampletest AS
$func$
SELECT *
FROM   sampletest
WHERE  eid IS NOT NULL
AND    dob BETWEEN COALESCE(_sd, -infinity) AND COALESCE(_ed, infinity)
$func$ LANGUAGE sql STABLE;
  • 不要引用语言名称。这是一个标识符。
  • Postgres 为timestampdate 类型提供special values -infinity and infinity。您只需使用COALESCE 将这些值默认为这些值。

SQL Fiddle(适用于第 9.3 页)。

除此之外:我建议使用标准 ISO 日期 '2014-11-10' 而不是 '11-10-2014',这可能会模棱两可并且会因不同的区域设置而中断。 The manual advises as much.

【讨论】:

  • 为了无限,让我更好地理解时间复杂性。 :) 谢谢
【解决方案2】:

您必须将函数定义为返回 set of sampletest,然后根据传递的参数返回 return different query restults

CREATE FUNCTION
  test_dob_dates(_sd date, _ed date)
RETURNS
  SETOF sampletest
AS
  $BODY$
    BEGIN
      IF _sd IS NOT NULL AND _ed IS NOT NULL THEN
        RETURN QUERY SELECT * FROM sampletest WHERE dob BETWEEN _sd AND _ed;
      ELSIF _sd IS NULL AND _ed IS NULL THEN
        RETURN QUERY SELECT * FROM sampletest WHERE dob IS NULL;
      ELSEIF _ed IS NOT NULL THEN
        RETURN QUERY SELECT * FROM sampletest WHERE dob <= _ed;
      ELSE
        RETURN QUERY SELECT * FROM sampletest WHERE dob >= _sd;
      END IF;
    END;
  $BODY$
LANGUAGE
  'plpgsql' VOLATILE;

eid IS NOT NULL 子句似乎是多余的,因为您已经将 eid 定义为 PRIMARY KEY,这意味着它永远不能为 NULL。

【讨论】:

  • 上面的代码是最优的并且在最好的时间执行。我看到有多行代码重复。如果我错了,请纠正我。
【解决方案3】:

SQL Fiddle

create function test_dob_dates(_sd date, _ed date)
returns setof sampletest as $body$
    select *
    from sampletest
    where
        eid is not null
        and (
            (_sd is null and _ed is null)
            or (_sd is not null and _ed is null and dob >= _sd)
            or (_sd is null and _ed is not null and dob <= _ed)
            or dob between _sd and _ed
        );
$body$ language sql stable;

【讨论】:

  • 感谢您的回复 :)
  • 我发现#Erwin Brandstetter 的帖子对无穷大(一些特殊值)的使用有一些理解。希望对你有帮助
猜你喜欢
  • 1970-01-01
  • 2018-10-02
  • 2021-12-15
  • 2013-04-15
  • 2012-10-16
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-05-29
相关资源
最近更新 更多