Postgresql 8.4 每个供应商至少有一个电话的客户

Postgresql 8.4 每个供应商至少有一个电话的客户,postgresql-8.4,Postgresql 8.4,我有这种情况。 我有客户,也有电话 我想让你知道一个clien是否每个约会至少有一个呼叫,如果他/她没有,我想要一个没有呼叫的de-dates数组 客户 身份证名称 1罗伯特 2鸟巢 召唤 id日期id\u客户端 1 2015-01-01 2 2 2015-01-31 1 id客户端1至少在2015-01-01所有日期都没有呼叫 您明白了吗?首先,必须有某种机制来确定您的查询检查的确切日期。从理论上讲,有无限多的日期,在此期间,给定的客户可能没有打过任何电话!你必须查询无穷大的子集 如

我有这种情况。 我有客户,也有电话 我想让你知道一个clien是否每个约会至少有一个呼叫,如果他/她没有,我想要一个没有呼叫的de-dates数组

客户 身份证名称 1罗伯特 2鸟巢

召唤 id日期id\u客户端 1 2015-01-01 2 2 2015-01-31 1

id客户端1至少在2015-01-01所有日期都没有呼叫


您明白了吗?

首先,必须有某种机制来确定您的查询检查的确切日期。从理论上讲,有无限多的日期,在此期间,给定的客户可能没有打过任何电话!你必须查询无穷大的子集

如果您对查询中要检查的少量日期的硬编码没有意见,那么我认为这就是您要查找的:

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)
  name  |      no_call_dates
--------+-------------------------
 nidia  | {2015-01-16,2015-01-31}
 robert | {2015-01-01,2015-01-16}
(2 rows)
我已经将三个日期硬编码并合并为一列“table literal”(如果您愿意),并将其与
client
表交叉连接,结果是每个客户机每个日期有一行。然后,该结果集可以与客户机id和调用日期上的
call
表保持连接。然后,您可以使用
where
子句仅筛选
call
表未能加入的行,这将生成一个无通话天数的结果集,仍然是每个客户机每个日期的结果集。然后,您可以按客户机分组,并使用
array\u agg()
aggregate函数构造客户机没有调用的日期数组

如果您不想硬编码日期,您可以提前准备一个日期表,并从
交叉连接
子句中进行选择,或者选择
调用
表中定义的所有日期(
选择与调用不同的d;
),或者使用一些更复杂的逻辑来选择要检查的日期。在所有这些情况下,您只需用适当的子查询替换“表文字”

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

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
;
输出:

  name  |      no_call_dates
--------+-------------------------
 nidia  | {2015-01-31,2015-01-15}
 robert | {2015-01-15,2015-01-01}
(2 rows)
  name  |      no_call_dates
--------+-------------------------
 nidia  | {2015-01-16,2015-01-31}
 robert | {2015-01-01,2015-01-16}
(2 rows)
在上面的查询中,我使用从1月1日到1月31日的日期范围(增量为15),生成了三个日期:2015-01-01、2015-01-16和2015-01-31。显然,对于您的情况,您可能希望增加一个,但我刚刚使用了15作为一个只有三个日期的简单示例


另外,我在
array\u agg()
调用中添加了一个
orderby
子句,因为按日期排序比随机排序更好。

我想是这样的。但你对这样的计划有什么期待?一个完整的算法文件的答案!为什么要放弃?慢慢谢谢我想我会找到解决办法的。你知道我如何创建一个虚拟的日期表并加入无通话的取消日期吗?这样:在两个日期之间?