[英]PostgreSQL query 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 不允许 function 作为参数,既不是行集也不是另一个 function。 我仍然可以在客户端或 plpgsql function 中使用字符串插值,但它容易出错并且难以测试和调试。 有什么建议吗?
在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
这听起来有点像您试图将太多代码放入数据库中。 如果您对满足特定谓词的特定关系的行感兴趣,只需在客户端代码中执行带有适当where
子句的select
语句。 拥有将谓词作为参数的视图正在重新发明 sql 已经很好地解决的轮子。
另一方面,我可以看到将查询本身存储在数据库中的论点,以便可以将它们组合成更大的报告。 这两个仍然由应用程序代码更好地处理。 我可能会通过使用擅长动态 sql 生成的库(例如 sqlalchemy)来解决类似的问题,然后将查询表示(sqlalchemy 表达式对象是“pickleable”)存储为数据库中的 blob。
换句话说,数据库是事实的代表,您将知识存储在其中。 应用程序有责任根据用户请求采取行动,当您发现自己在数据上定义转换时,实际上更多的是预测和实施实际用户的请求,而不仅仅是忠实地保存知识。
当架构不可避免地发生变化时,最好使用视图,因此您可以将不需要了解新架构的旧应用程序留在有效的 state 中。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.