我有一个sql函数,它执行一个简单的sql select语句:

CREATE OR REPLACE FUNCTION getStuff(param character varying)
  RETURNS SETOF stuff AS
$BODY$
    select *
    from stuff
    where col = $1
$BODY$
  LANGUAGE sql;

现在,我像这样调用此函数:

select * from getStuff('hello');

如果我需要订购和限制order bylimit个子句的结果,我有什么 Select ?

我猜这样的问题:

select * from getStuff('hello') order by col2 limit 100;

效率不是很高,因为表stuff中的所有行都将由函数getStuff返回,然后才按限制排序和切片.

但是,即使我是对的,也没有简单的方法来传递SQL语言函数的order by参数.只能传递值,不能传递SQL语句的一部分.

另一种 Select 是用plpgsql语言创建函数,其中可以构造查询并通过EXECUTE执行它.但这也不是一个很好的方法.

那么,有没有其他方法可以做到这一点呢? 或者你会 Select 什么选项?在函数之外排序/限制,还是plpgsql?

我正在使用PostgreSQL9.1.

编辑

我修改了CREATE Function语句,如下所示:

CREATE OR REPLACE FUNCTION getStuff(param character varying, orderby character varying)
  RETURNS SETOF stuff AS
$BODY$
    select t.*
    from stuff t
    where col = $1
    ORDER BY
        CASE WHEN $2 = 'parent' THEN t.parent END,
        CASE WHEN $2 = 'type' THEN t."type" END, 
        CASE WHEN $2 = 'title' THEN t.title END

$BODY$
  LANGUAGE sql;

This throws:

错误:大小写类型字符变化和整数不匹配 ŘáDKA 13:当$1=‘Parent’时,则t.Parent

stuff表格如下所示:

CREATE TABLE stuff
    (
      id integer serial,
      "type" integer NOT NULL,
      parent integer,
      title character varying(100) NOT NULL,
      description text,
      CONSTRAINT "pkId" PRIMARY KEY (id),
    )

编辑2

我读DEM代码读得很差.我已将其更正为有疑问的.这个代码对我很有效.

推荐答案

There is nothing wrong with a plpgsql function for anything a little more complex. The only situation where performance can suffer is when a plpgsql function is nested, because the query planner cannot further optimize the contained code in the context of the outer query which may or may not make it slower.
More details in this later answer:

这比查询中的CASE个子句要简单得多:

CREATE OR REPLACE FUNCTION get_stuff(_param text, _orderby text, _limit int)
  RETURNS SETOF stuff AS
$func$
BEGIN
   RETURN QUERY EXECUTE '
      SELECT *
      FROM   stuff
      WHERE  col = $1
      ORDER  BY ' || quote_ident(_orderby) || ' ASC
      LIMIT  $2'
   USING _param, _limit;
END
$func$  LANGUAGE plpgsql;

呼叫:

SELECT * FROM get_stuff('hello', 'col2', 100);

注意事项

使用RETURN QUERY EXECUTE一次性返回查询结果.

Use quote_ident() for identifiers to safeguard against SQLi.
Or format() for anything more complex. See:

将参数值与USING子句一起传递,以避免再次进行强制转换、引号和SQLI.

请注意,不要在参数和列名之间创建命名冲突.在本例中,我为参数名称添加了下划线(_)作为前缀.这只是我个人的喜好.

编辑后的第二个函数无法工作,因为您只返回parent,而返回类型声明为SETOF stuff.您可以声明您喜欢的any返回类型,但实际返回值必须与声明匹配.你可能会想要用RETURNS TABLE美元.

Database相关问答推荐

当我们需要触发程序的返回值时?

哪个能够存储 1 亿条记录的嵌入式数据库具有高效的 C 或 C++ API

有使用 H2 数据库的实际经验吗?

什么是非规范化 mysql 数据库的好方法?

操作错误:FATAL: database "django" does not exist

如何在 Windows 中安装 InfluxDB?

如何关闭 Rails 中的updated_at列?

设置默认数据库连接 Rails

将 XML 存储在数据库中是否不好?

文件访问速度与数据库访问速度

Hibernate、spring、JPS 和隔离 - 不支持自定义隔离

在 SQL 数据库之间共享数据

审计表:一个表或一个表的每个字段

MySQL 转储所有数据库并在导入时创建(或重新创建)它们?

日期范围重叠判断约束

限制一个 sqlite 表的最大行数

什么是非关系数据库的例子?

从 CSV 文件填充 Android 数据库?

App=EntityFramework 在 Sql 连接字符串中有什么作用?

数据库效率 - 每个用户的表与用户表