每个供应商至少有一次呼叫的客户端

时间:2015-01-30 16:27:57

标签: postgresql-8.4

我有这种情况。 我有客户,我有电话 我想知道,如果一个客户每个日期至少有1个电话,如果他/她没有,我想要一个没有电话的日期数组。

客户端 id名称 1罗伯特 2 nidia

呼叫 id date id_client 1 2015-01-01 2 2 2015-01-31 1

ID客户端1最近没有呼叫2015-01-01

你知道吗?

1 个答案:

答案 0 :(得分:0)

首先,必须有一些机制来确定查询检查的日期。理论上有一个无限数量的日期,在此期间,给定的客户可能已拨打任何电话!您必须查询该无穷大的子集。

如果您在查询中使用硬编码确定需要检查的少量日期,那么我认为这是您正在寻找的内容:

drop table if exists call;
drop table if exists client;

create table client (id int, name varchar(32), primary key (id) );
insert into client (id,name) values (1,'robert'), (2,'nidia');

create table call (id int, d date, client_id int references client(id), primary key (id) );
insert into call (id,d,client_id) values (1,'2015-01-01',(select id from client where name='nidia')), (2,'2015-01-31',(select id from client where name='robert'));

select
    cl.name,
    array_agg(ds.d) no_call_dates
from
    client cl
    cross join (select '2015-01-01'::date d union all select '2015-01-15' union all select '2015-01-31') ds
    left join call ca on ca.client_id=cl.id and ca.d=ds.d
where
    ca.id is null
group by
    cl.name
;

输出:

  name  |      no_call_dates
--------+-------------------------
 nidia  | {2015-01-31,2015-01-15}
 robert | {2015-01-15,2015-01-01}
(2 rows)

我已经硬编码并将三个日期合并为单列"表格文字" (如果愿意的话)并使用client表交叉加入,导致每个客户端每行一行。然后,该结果集可以与客户端ID和呼叫日期上的call表保持连接。然后,您可以使用where子句仅过滤call表无法加入的行,这会产生无通话天数的结果集,仍然是每个客户端的日期。然后,您可以按客户端进行分组,并使用array_agg()聚合函数构建客户端进行调用的日期数组。

如果您不想对日期进行硬编码,您可以提前准备一份日期表,并从cross join子句中选择,或者选择{中定义的所有日期{1}} table(call),或者使用一些更复杂的逻辑来选择要检查的日期。在所有这些情况下,您只需替换"表格文字"使用适当的子查询。

编辑:是的,这非常可行。您可以使用generate_series()函数生成整数序列并将其添加到固定的开始日期,从而生成日期范围。如前所述,这可以在交叉连接子查询中完成。避免重复的好方法是使用CTE设置开始和结束日期:

select distinct d from call;

输出:

select
    cl.name,
    array_agg(ds.d order by ds.d) no_call_dates
from
    client cl
    cross join (with dr as (select '2015-01-01'::date s, '2015-01-31'::date e) select s+generate_series(0,e-s,15) d from dr) ds
    left join call ca on ca.client_id=cl.id and ca.d=ds.d
where
    ca.id is null
group by
    cl.name
;

在上面的查询中,我使用1月1日到1月31日的日期范围生成三个日期,2015-01-01,2015-01-16和2015-01-31,增量为15.显然对于你的情况,你可能想要增加一个,但我只用了15个只有三个日期的简单例子。

此外,我在 name | no_call_dates --------+------------------------- nidia | {2015-01-16,2015-01-31} robert | {2015-01-01,2015-01-16} (2 rows) 电话中添加了order by条款,因为按日期排序可以更好,而非随机。