【问题标题】:How to pass a parameter into a date function如何将参数传递给日期函数
【发布时间】:2015-08-25 20:15:32
【问题描述】:

我正在尝试创建一个简单的函数,但我似乎无法将参数传递给日期函数。
这是函数:

CREATE OR REPLACE FUNCTION test(source int,days text)
RETURNS integer AS $totals$
declare
    totals integer;
BEGIN

   select 
           count(id) into totals
     from  ad
    where
       createdate::date = date(current_date - interval '$2' day) and
       source = $1;

   RETURN totals;

END;
$totals$ LANGUAGE plpgsql;

【问题讨论】:

  • 您的 Postgres 版本、表定义和您收到的错误消息将是 essential 详细信息。
  • 是的,这里的答案有效。我正在测试该功能的旧版本...感谢您的深入回答。

标签: sql postgresql parameter-passing plpgsql date-arithmetic


【解决方案1】:

@IMSoP 已经揭示了您的语法错误。但是,这可以通过多种方式更简单、更快、更清晰。

CREATE OR REPLACE FUNCTION test(_source int, _days int)
  RETURNS integer AS
$func$
SELECT count(*)::int
FROM   ad a
WHERE  a.source = $1
AND    a.createdate::date = current_date - $2
$func$  LANGUAGE sql STABLE;
  • 首先,要从date 中减去天数,您可以减去integer 数字。因此,我在这里使用integer 参数。

  • 对于像这样的简单函数,您不需要 plpgsql。改用 SQL 函数 - 它可以在更大查询的上下文中“内联”,从而在某些情况下得到更好的优化。

  • 函数可以是STABLE

  • 您的函数中内置了命名冲突source 显然也是一个列名。尽量避免这种情况。一种常见的做法是在变量和参数前加上下划线(否则没有特殊含义)。您还可以对列名进行表限定和/或在函数名前附加参数名(或使用位置参数)以明确。我在这里都做了。

  • 假设id 是您的PK 列,因此定义NOT NULLcount(*)count(id) 相同,更短且更便宜。我转换为integer,因为count() 将返回bigint

但是,在这里走神,我怀疑您命名不准确的列createdate 实际上不是date,而是timestamp(问题中缺少基本表定义) .在这种情况下,以不同的方式表达查询会更有效:

CREATE OR REPLACE FUNCTION test(_source int, _days int)
  RETURNS integer AS
$func$
SELECT count(*)::int
FROM   ad a
WHERE  a.source = $1
AND    a.createdate >= now() - interval '1 day' * $2
AND    a.createdate <  now() - interval '1 day' * ($2 - 1)
$func$ LANGUAGE sql STABLE;
  • 这个表达式是sargable,因此效率更高。它还可以在(createdate) 上使用普通的索引,或者更好地在(source, createdate) 上使用——这对大表很重要。

  • 还演示了另一种减去天数的方法。您可以乘以interval '1 day'。相关:

【讨论】:

    【解决方案2】:

    这是无效的语法:interval '$2' day。变量不仅在 SQL 运行之前被交换到位,您还需要将正确类型的值传递给函数。

    您可能打算将字符串 'day' 连接到字符串 (text) 变量 $2 的末尾,也称为 days(不是文字字符串 '$2')。所以$2 || 'day'days || 'day'

    由于这不是单个文字,因此您需要显式转换,而不仅仅是类型标签,例如 CAST($2 || 'day' AS interval)(days || 'day')::interval

    【讨论】:

    • 感谢您的回复。我试过这个: date = date(current_date - (days || 'day')::interval) 螺母它不起作用。这和你预期的一样吗?
    • @user1609817 请澄清“不起作用”。您是否收到错误消息 - 如果是,是什么消息?它会做“错误”的事情吗?如果是,它会做什么以及您希望它做什么?
    • 非常抱歉。我正在针对不同的功能进行测试。您的解决方案有效!非常感谢。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2023-03-19
    • 1970-01-01
    • 2015-10-30
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多