我使用的是 PostgreSQL 9.3.9,我有一个名为 list_all_upsells 的过程,它在月初和月末进行处理。 (有关示例数据,请参阅 sqlfiddle.com/#!15/abd02)例如,下面的代码将列出 10 月份的追加销售帐户数:
select COUNT(up.*) as "Total Upsell Accounts in October" from
list_all_upsells('2015-10-01 00:00:00'::timestamp, '2015-10-31 23:59:59'::timestamp) as up
where up.user_id not in
(select distinct user_id from paid_users_no_more
where concat(extract(month from payment_stop_date),'-',extract(year from payment_stop_date))<>
concat(extract(month from payment_start_date),'-',extract(year from payment_start_date)));
list_all_upsells 过程如下所示:
DECLARE
payor_email_2 text;
BEGIN
FOR payor_email_2 in select distinct payor_email from paid_users LOOP
return query
execute
'select paid_users.* from paid_users,
(
select payment_start_date as first_time from paid_users
where payor_email = $3
order by payment_start_date limit 1
) as dummy
where payor_email = $3
and payment_start_date > first_time
and payment_start_date between $1 and $2
and first_time < $1'
using a, b, payor_email_2;
END LOOP;
return;
END
我希望能够在我们有记录的所有月份运行此程序,并像这样在一个表中一起查询数据:
Month | Total Upselled Accounts
---------------------------------
08/2014 | 23
09/2014 | 35
ETC...
10/2015 | 56
我有一个查询要获取我们开展业务的每个月的第一天和最后一天:
select distinct date_trunc('month', payment_start_date)::date as startmonth
from paid_users ORDER BY startmonth;
月末:
SELECT distinct (date_trunc('MONTH', payment_start_date) +
INTERVAL '1 MONTH - 1 day')::date as endmonth from paid_users
ORDER BY endmonth;
现在我如何创建一个函数来循环遍历 list_all_upsells
并获取每个月的计数? IE。 startmonth
的第一个查询给了我 2014-03-01, 2014-04-01, ...to 2015-10-01 而 endmonth
的第二个查询给了我2014-03-31、2014-04-30、...至 2015-10-31。我想在这几个月的每个月都运行 list_all_sells
,这样我就可以得到每个月我们有多少追加销售帐户的总计数
我的 paid_users
表如下所示:
CREATE TABLE paid_users
(
user_id integer,
user_email character varying(255),
payor_id integer,
payor_email character varying(255),
payment_start_date timestamp without time zone DEFAULT now()
)
paid_users_no_more
:
CREATE TABLE paid_users_no_more
(
user_id integer,
payment_stop_date timestamp without time zone DEFAULT now()
)
最佳答案
您的函数有几个问题,让我们从这里开始。简而言之,(1)您只需要一个参数来指示月份,使用月份的开始和结束会给自己带来问题; (2) 您不需要动态查询,因为您没有更改标识符(表名或列名); (3) 你不需要循环; (4) 你的逻辑是错误的。我还可以提到 PostgreSQL 使用 函数 并且它们都以类似 CREATE FUNCTION list_all_upsells(...)
的行开头但这太挑剔了。
从逻辑开始:显然,一个由他的电子邮件地址识别的用户从某个 payment_start_date
订阅了一个订阅。直到某个payment_stop_date
并且可以多次执行此操作。您正在寻找那些在相关月份之前进行首次订阅,并且在相关月份开始新订阅但不是首次订阅的用户。在这种情况下,过滤器 payment_start_date > first_time
是无用的,因为您已经筛选出在相关月份之前的第一个订阅 ( first_time < $1
) 和一个新订阅 ( payment_start_date BETWEEN $1 AND $2
)。
第 (1)、(2) 和 (3) 点只有在函数内部重写查询时才会变得明显:
CREATE FUNCTION list_all_upsells(<b>timestamp</b>) RETURNS SETOF paid_users AS $$
SELECT paid_users.*
FROM paid_users
JOIN ( -- This JOIN keeps only those rows where the payor_email has a prior subscription
SELECT DISTINCT payor_email,
first_value(payment_start_date) OVER (PARTITION BY payor_email ORDER BY payment_start_date) AS dummy
FROM paid_users
WHERE payment_start_date < date_trunc('month', $1)
) dummy USING (payor_email)
-- This filter keeps only those rows with new subscriptions in the month
WHERE date_trunc('month', payment_start_date) = date_trunc('month', $1)
$$ LANGUAGE sql STRICT;
由于函数体已缩减为单个 SQL 语句,函数现在是一个 sql
。语言功能,比plpgsql
更高效.您现在只提供一个参数,可以是您想要数据的月份中的任何时刻,因此 list_all_upsells(LOCALTIMESTAMP)
会给你当月的结果。根据您发布的查询,它将是:
SELECT count(up.*) AS "Total Upsell Accounts in October"
FROM list_all_upsells(LOCALTIMESTAMP) up
WHERE up.user_id NOT IN
(SELECT DISTINCT user_id FROM paid_users_no_more
WHERE date_trunc('month', payment_stop_date) <>
date_trunc('month', up.payment_start_date)
);
顺便说一下,这真的回避了为什么你有 table paid_users_no_more
的问题.为什么不简单地添加一列 payment_stop_date
到表 paid_users
?该列在哪里 NULL
用户仍然订阅。但是整个查询很奇怪,因为 list_all_upsells()
当月返回新订阅,那么为什么要在其他时间 处理已取消的订阅呢?
现在开始您的真正问题:
SELECT months.m "Month", coalesce(count(up.*), 0) "Total Upselled Accounts"
FROM generate_series('2014-08-01'::timestamp,
date_trunc('month', LOCALTIMESTAMP),
'1 month') AS months(m)
LEFT JOIN list_all_upsells(months.m) AS up ON date_trunc('month', payment_start_date) = m
GROUP BY 1
ORDER BY 1;
Generate a series of months从某个开始月份到当前月份,然后计算每个月的新订阅数,可能为 0。
关于postgresql - 如何创建一个循环遍历 PostgreSQL 中另一个函数的函数?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/33001854/