我有一些范围折叠逻辑(基于 http://wiki.postgresql.org/wiki/Range_aggregation ),我想在各种不同的列分区上重复使用。
现在我正在使用 PHP 完成此操作。我有一个类似于以下的函数,它返回我要运行的查询并替换相关列:
function getIntervalsQueryForPartition($partitions = array())
{
// ... there is some validation logic here, not relevant to question
$cols = implode(', ', $partitions) . ' ';
return <<<SQL
SELECT $cols, MIN(start_date) start_date, MAX(end_date) end_date
FROM (
SELECT $cols, start_date, end_date,
MAX(new_start) OVER (
PARTITION BY $cols
ORDER BY start_date, end_date
) AS left_edge
FROM (
SELECT $cols, start_date, end_date,
CASE WHEN GREATEST(
MIN(start_date) OVER (
PARTITION BY $cols
ORDER BY start_date, end_date
ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW
),
start_date - INTERVAL '90 days'
) < (
MAX(end_date) OVER (
PARTITION BY $cols
ORDER BY start_date, end_date
ROWS BETWEEN UNBOUNDED PRECEDING AND 1 PRECEDING
)
)
THEN NULL
ELSE start_date
END AS new_start
FROM product_activity
) s1
) s2
GROUP BY $cols, left_edge
SQL;
}
最终,product_activity
上有许多不同的列分区,我希望对其执行相同的窗口化和聚合。显然,我不希望只在分区略有不同的地方复制和粘贴查询:因此上面的 PHP 函数。
我怎样才能完全在 postgres 中完成相同的抽象?这可以用存储过程来完成吗?我希望 dba 能够针对不同的分区调用此查询,而无需复制和粘贴它,然后编辑指定列的所有 7 个位置。
最佳答案
您可以像在 PHP 中一样编写函数。由于特定的 pl/pgSQL 限制,最简单的选择是编写一个带有一个文本参数并返回一组记录的函数。
create or replace function func (cols text)
returns setof record language plpgsql as $$
begin
return query execute format (
'SELECT %s, MIN(start_date) start_date, MAX(end_date) end_date
FROM (
SELECT %s, start_date, end_date,
MAX(new_start) OVER (
PARTITION BY %s
ORDER BY start_date, end_date
) AS left_edge
FROM (
SELECT %s, start_date, end_date,
CASE WHEN GREATEST(
MIN(start_date) OVER (
PARTITION BY %s
ORDER BY start_date, end_date
ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW
),
start_date - INTERVAL ''90 days''
) < (
MAX(end_date) OVER (
PARTITION BY %s
ORDER BY start_date, end_date
ROWS BETWEEN UNBOUNDED PRECEDING AND 1 PRECEDING
)
)
THEN NULL
ELSE start_date
END AS new_start
FROM product_activity
) s1
) s2
GROUP BY %s, left_edge',
cols, cols, cols, cols, cols, cols, cols);
end $$;
此方法的唯一缺点是调用函数的方式 - 它必须强制转换为显式复合类型。
select * from func('a1, a2')
as (a1 int, a2 int, start_date date, end_date date);
select * from func('a1, a3, a5')
as (a1 int, a3 int, a5 int, start_date date, end_date date);
关于php - 如何集中重复使用但每次使用不同分区的复杂窗口查询,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/23352285/