php - 如何集中重复使用但每次使用不同分区的复杂窗口查询

标签 php postgresql postgresql-9.1 plpgsql

我有一些范围折叠逻辑(基于 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/

相关文章:

php - 为什么 COM 类在 PHP 5.4.5 中不再存在?

python - 如何从 Django 中的 auth_user 表访问自定义列?

postgresql - 在 PostgreSQL 中重命名枚举项

postgresql - 我忘记了我在安装 PostgreSQL 时输入的密码

unix - psql :ERROR: syntax error at or near "" LINE 1: 

php - 从php更新mysql数据库中的多条记录

php - 如何关闭 PHP 通知?

php - 在 PHP 中,如何调用在字符串中插入的函数?

sql - PostgreSQL:获取列的最小值及其相关城市

PostgreSQL 错误 : INSERT has more target columns than expressions, 当它不存在时