【问题标题】:Can someone explain this SQL? (and how may I 'parametrize' it and invoke as a function?)有人可以解释这个 SQL 吗? (以及如何“参数化”它并作为函数调用?)
【发布时间】:2012-01-04 11:14:39
【问题描述】:

我遇到了这段'voodoo' SQL,它被用来对表中的数据进行自定义分组。我想了解它是如何变魔术的,但我无法理解它。那里的 SQL 专家可以用简单的英语向不太懂 SQL 的人解释这个 sn-p 的各个部分,它可以发挥它的魔力吗?

select ceil(rnk/10.0) as grp,
       col1, col2, col3, col4, col5, col6, col7
from (select e.col1, e.col2, e.col3, e.col4, e.col5, e.col6, e.col7,
             (select count(*) 
              from mytable d
              where e.col1 > d.col1)+1 as rnk
      from mytable e) x
order by grp;

上面我似乎无法理解的部分 SQL 是返回列“x”的内部 SQL:

(select count(*) from mytable d
                where e.col1 > d.col1)+1 as rnk
                from mytable e
                ) x

我希望能够自行运行该查询:

select count(*) from mytable d
                where e.col1 > d.col1)+1 as rnk
                from mytable e

但是,当我这样做时,我得到了错误:

错误:“+”处或附近的语法错误第 2 行:其中 e.col1 > d.col1)+1 作为 rnk

那么,那里发生了什么?!

另外,当前的 SQL 是用数字 10 硬编码的。我想在它周围包装一个函数,以便能够使用 10 以外的数字调用该函数。

后端数据库是 PostgreSQL,所以函数会在 PL/pgSQL 中。这是我第一次尝试编写这样的函数 - 但是,这并不完全正确,因为我想返回指定列的多行 - 所以下面的函数需要进行一些修改,不完全确定如何:

CREATE OR REPLACE FUNCTION my_custom_grouping(in integer, 
                                              out grp integer,
                                              out col1 double,
                                              out col2 double,
                                              out col3 double,
                                              out col4 double,
                                              out col5 double,
                                              out col6 double,
                                              out col7 double
                                              )

    AS $$ SELECT 
       ceil(rnk/$1) as grp,
                col1, col2, col3, col4, col5, col6, col7
                from (
                select e.col1, e.col2, e.col3, e.col4, e.col5, e.col6, e.col7,
                (select count(*) from mytable d
                where e.col1 > d.col1)+1 as rnk
                from mytable e
                ) x
                order by grp;
    $$
    LANGUAGE SQL;

除了不返回多于一行的函数之外,我不确定这是否是参数化查询的最佳方法 - 我在正确的路径上吗? - 如果是,我将如何修改上面的函数以返回多行而不是当前的单个“行”(即“多列”输出)?

这是对函数返回的数据运行聚合函数(按“grp”分组)的正确方法吗?

【问题讨论】:

  • 您不能单独运行子查询,因为它引用了外部查询:e.col1。然而,整个构造是无效的,因为我们可以为此使用窗口函数rank()。我在回答中使用了它。
  • 我已重新格式化初始查询 - 这可能会使其中发生的事情更加清晰。

标签: sql postgresql plpgsql


【解决方案1】:

您的(简化的!)函数可能如下所示:

CREATE OR REPLACE FUNCTION my_custom_grouping(integer)
RETURNS TABLE (
   grp integer,
   col1 double precision,
   col2 double precision,
   col3 double precision,
   col4 double precision,
   col5 double precision,
   col6 double precision,
   col7 double precision) AS
$BODY$
    SELECT ceil(rank() OVER (ORDER BY col1) / $1)::int as grp
          ,col1, col2, col3, col4, col5, col6, col7
    FROM   mytable 
    ORDER  BY 1;
$BODY$ LANGUAGE SQL;

要点:

  • 请注意,这是language SQL,因此不是 PL/pgSQL 函数。你也可以使用language plpgsql,但这不是必需的。

  • 我用window function rank() 替换了你的巫毒教核心,它应该完全一样,只是更简单。

  • 我还完全删除了子查询。没必要。

  • double 类型在 PostgreSQL 中称为 double precision

  • 要返回多行,像我一样将函数定义为RETURNS SETOF recordRETURNS TABLE

  • ORDER BY可以使用位置参数,所以不用再拼出第一列的计算:ORDER BY 1
    但是,同一grp 中有多个行。向ORDER BY 子句添加更多列或表达式以达到稳定的排序顺序。

【讨论】:

  • +1 用于链接到窗口函数 - 它打开了一个全新的世界(双关语无意!)。
猜你喜欢
  • 1970-01-01
  • 2020-02-23
  • 1970-01-01
  • 2022-01-18
  • 2021-03-05
  • 1970-01-01
  • 1970-01-01
  • 2011-04-01
  • 1970-01-01
相关资源
最近更新 更多