PostgreSQL查询分解

时间:2011-08-12 16:14:37

标签: sql postgresql view decomposition

我无法分解简单的SQL查询。我使用PostgreSQL,但我的问题也与其他RDBMS有关。

考虑以下示例。我们有表订单,我们希望找到第一个订单,之后总金额超过了某个限制:

drop table if exists orders cascade;

/**
Table with clients' orders
*/
create table orders(
date timestamp,
amount integer
/**
Other columns omitted
*/
);

/**
Populate with test data
*/
insert into orders(date,amount) 
values
('2011-01-01',50),
('2011-01-02',49),
('2011-01-03',2),
('2011-01-04',1000);

/**
Selects first order that caused exceeding of limit 
*/
create view first_limit_exceed
as
select min(date) from
(
    select  o1.date
    from orders o1,
         orders o2
    where o2.date<=o1.date
    group by o1.date
    having sum(o2.amount) > 100
) limit_exceed;

/**
returns "2011-01-03 00:00:00"
*/
select * from first_limit_exceed;

现在让我们更难解决问题。考虑我们只想查找满足某些谓词的行的总量。我们有很多这样的谓词,并且创建单独版本的视图first_limit_exceed将是可怕的代码重复。所以我们需要一些方法来创建参数化视图并传递过滤的行集或谓词本身。 在Postgres中,我们可以使用查询语言函数作为参数化视图。但Postgres不允许函数作为参数既不是行也不是另一个函数。 我仍然可以在客户端或plpgsql函数中使用字符串插值,但它容易出错并且难以测试和调试。 有什么建议吗?

2 个答案:

答案 0 :(得分:2)

PostgreSQL 8.4及以后:

SELECT  *
FROM    (
        SELECT  *,
                SUM(amount) OVER (ORDER BY date) AS psum
        FROM    orders
        ) q
WHERE   psum > 100
ORDER BY
        date
LIMIT 1

将所需的任何谓词添加到内部查询中:

SELECT  *
FROM    (
        SELECT  *,
                SUM(amount) OVER (ORDER BY date) AS psum
        FROM    orders
        WHERE   date >= '2011-01-03'
        ) q
WHERE   psum > 100
ORDER BY
        date
LIMIT 1

答案 1 :(得分:-1)

听起来有点像你试图将太多代码放入数据库中。如果您对满足特定谓词的某个关系的行感兴趣,只需在客户端代码中执行带有适当select子句的where语句。拥有将谓词作为参数的视图正在重新发明sql已经很好地解决的轮子。

另一方面,我可以看到一个参数,用于将查询本身存储在数据库中,以便将它们组合成更大的报告。这两个应用程序代码仍然可以更好地处理。我可能通过使用擅长动态sql生成的库(例如sqlalchemy)来处理这样的问题,然后将查询表示(sqlalchemy表达式对象是'pickleable')存储为数据库中的blob。

换句话说,数据库是事实的代表,你将知识存储在其中。应用程序有责任对用户请求进行操作,当您发现自己定义数据转换时,这实际上更多的是预测和实现实际用户的请求,而不仅仅是忠实地保存知识。 / p>

当架构不可避免地发生变化时,最好使用视图,因此您可以将不需要了解新架构的旧应用程序保留在工作状态。