【问题标题】:Convert numeric to string inside a user-defined function在用户定义的函数中将数字转换为字符串
【发布时间】:2013-06-03 00:29:03
【问题描述】:

我正在尝试在用户定义的函数中将数值变量调用/转换为字符串。我在考虑使用to_char,但没有通过。

我的功能是这样的:

create or replace function ntile_loop(x numeric)
returns setof numeric as 
$$
  select

  max("billed") as _____(to_char($1,'99')||"%"???) from 
      (select "billed", "id","cm",ntile(100) 
      over (partition by "id","cm" order by "billed")
      as "percentile" from "table_all") where "percentile"=$1
      group by "id","cm","percentile";
$$
language sql;

我的目的是定义一个新变量“x%”作为它的名称,其中 x 变化作为函数输入。在上下文中,x 是数字,稍后将在函数中作为数字再次调用(这部分代码未包含在上面的示例中)。

我要返回的内容:

我只是想返回一段代码,这样每次我更改百分位数时,我就不必一次又一次地运行这段代码。我想计算 5, 10, 20, 30, ....90th 百分位数,并将每个 id+cm 组的所有这些都显示在同一张表中。

这就是为什么我在考虑宏或函数,但没有找到我喜欢的任何解决方案。

感谢您的回答。是的,我一定会在学习的同时阅读基础知识。今天是我使用 SQL 的第二天,但必须立即生成一些结果。

【问题讨论】:

  • 发布完整功能...
  • I also know that returns setof numeric is not correct, but have no idea what else I could use. 我们也不知道你想要返回什么。样本输出怎么样?而it didn't pass 不是有效的 Postgres 错误消息。你真正得到了什么?
  • _____??? 在那里做什么?它们实际上是你的代码的一部分,还是你想告诉我们一些关于它的事情?
  • 也相关:您的 PostgreSQL 版本 ...
  • 了解SQL的第一件事是“考虑宏或函数”应该是你最后的手段。您的第一种方法应该始终是建立一个单一的查询来提供您需要的结果。 DBMS 可能比您在研究如何循环或以其他方式查询数据方面做得更好。

标签: sql postgresql types user-defined-functions plpgsql


【解决方案1】:

numeric 转换为text 是您最少的问题。

我的目的是定义一个新变量“x%”作为它的名字,用x 随函数输入而变化。

  • 首先:SQL 函数中没有变量。 SQL 函数只是有效 SQL 语句的包装器。输入和输出参数可以命名,但名称是静态的,不是动态的。

  • 您可能会想到PL/pgSQL function,其中有包括变量在内的过程元素。不过,参数名称仍然是静态。 plpgsql 中没有动态变量名。您可以使用 EXECUTE 执行动态 SQL,但这完全不同。

  • 虽然可以使用像"123%" 这样的名称 声明一个静态 变量,但这样做确实非常罕见所以。也许是为了故意混淆代码?除此之外:不要。使用正确、简单、合法、小写的变量名,无需双引号,也不会在拼写错误后出现意外情况。

  • 由于窗口函数 ntile() 返回 integer 并且您对结果运行相等性检查,因此输入参数应该是 integer,而不是 numeric

  • 对于assign a variable in plpgsql,您可以对单个变量使用赋值运算符:=,或对任意数量的变量使用SELECT INTO。无论哪种方式,您都希望查询返回单行,或者您必须返回loop

  • 如果您想要所选百分位数的最大 billed,则不需要 GROUP BY x, y。这可能会返回多行并且不会执行您想要的操作。使用不带GROUP BY 的普通max(billed) 来获得单行。

  • 你不需要双引号perfectly legal column names

一个有效的函数可能如下所示。这不完全是你想要做的,这是无法做到的。但它可能会让你更接近你真正需要的东西。

CREATE OR REPLACE FUNCTION ntile_loop(x integer)
RETURNS SETOF numeric as 
$func$
DECLARE
   myvar text;
BEGIN

SELECT INTO myvar  max(billed)
FROM  (
   SELECT billed, id, cm
         ,ntile(100) OVER (PARTITION BY id, cm ORDER BY billed) AS tile
   FROM   table_all
   ) sub
WHERE  sub.tile = $1;

-- do something with myvar, depending on the value of $1 ...
END
$func$ LANGUAGE plpgsql;

长话短说,在尝试创建复杂函数之前,您需要学习基础知识

普通 SQL

Q更新后:

我想计算第 5、10、20、30、....90 个百分位数并显示 对于每个 id+cm 组,它们都在同一个表中。

这个简单的查询应该可以解决所有问题:

SELECT id, cm, tile, max(billed) AS max_billed
FROM  (
   SELECT billed, id, cm
         ,ntile(100) OVER (PARTITION BY id, cm ORDER BY billed) AS tile
   FROM   table_all
   ) sub
WHERE (tile%10 = 0 OR tile = 5)
AND    tile <= 90
GROUP  BY 1,2,3
ORDER  BY 1,2,3;

% .. modulo operator
GROUP BY 1,2,3 .. positional parameter

【讨论】:

  • 这是我在回答中草拟的所有内容,大部分都说得更好,包括更好地尝试理解奇怪的嵌套GROUP BY,而不是我设法理解。
  • 我在回答中确实试图提到的一件事(我已删除):使用过程语言构建 SQL 时(例如,使用EXECUTE 的 PL/pgSQL 或 PHP / Ruby / 数据库之外的任何内容)理论上,您可以根据以前的输入动态创建列名。然而,动态变量/字段名称通常会带来比它们被错误地引入的解决方案更多的问题。
  • @IMSoP:我完全同意。虽然可以动态地创建一个函数来获取某个变量名,但很有可能,有一个更简单的解决方案即将到来。一个人需要非常了解 plpgsql 才能跳过那些燃烧的循环。但足够了解它的人可能知道更简单的解决方案。
  • @JohnSmith:提示?您的意思是,就像我的答案中指向优秀手册的许多链接一样?我还添加了一个简单的 SQL 查询,它应该适合您的 Q 更新。无需跳过燃烧循环,但对于您的 second day to use SQL 来说仍然是非常先进的东西。
  • 另外我认为你代码的最后一行应该是order by 1,2,3
【解决方案2】:

【讨论】:

    猜你喜欢
    • 2018-03-17
    • 2017-12-03
    • 2013-11-27
    • 1970-01-01
    • 1970-01-01
    • 2018-11-24
    • 1970-01-01
    相关资源
    最近更新 更多