首次呼叫和最后一次呼叫是同一个人的呼叫者

时间:2020-02-02 02:08:58

标签: sql sql-server database

我有一个电话日志表,其中包含有关呼叫者通话记录的信息。我想找出在给定日期的第一个和最后一个呼叫对象是同一个人的呼叫者。

Callerid  Recipientid        DateCalled
1          2            2019-01-01 09:00:00.000
1          3            2019-01-01 17:00:00.000
1          4            2019-01-01 23:00:00.000
2          5            2019-07-05 09:00:00.000
2          5            2019-07-05 17:00:00.000
2          3            2019-07-05 23:00:00.000
2          5            2019-07-06 17:00:00.000
2          3            2019-08-01 09:00:00.000
2          3            2019-08-01 17:00:00.000
2          4            2019-08-02 09:00:00.000
2          5            2019-08-02 10:00:00.000
2          4            2019-08-02 11:00:00.000

Expected Output
Callerid   Recipientid     Datecalled
2             5            2019-07-05
2             3            2019-08-01
2             4            2019-08-02

我编写了以下查询,但无法获取返回的id。任何帮助将不胜感激!

select pl.callerid,cast(pl.datecalled as date) as datecalled
from phonelog pl inner join (select callerid, cast(datecalled as date) as datecalled, 
                             min(datecalled) as firstcall, max(datecalled) as lastcall
                             from phonelog
                             group by callerid, cast(datecalled as date)) as x
on pl.callerid = x.callerid and cast(pl.datecalled as date) = x.datecalled
and (pl.datecalled = x.firstcall or pl.datecalled = x.lastcall)
group by pl.callerid, cast(pl.datecalled as date) 
having count(distinct recipientid) = 1

7 个答案:

答案 0 :(得分:2)

Another dbFiddle option

首先,我的预查询(PQ别名)是我每天为给定的客户获取的最小和最大通话时间,但同时也要确保该人在给定的一天中至少有2个电话通话。从那以后,我重新加入到给定日期该人的第一个(MIN)呼叫的电话日志表。然后,我又参加了同一天同一人的LAST(MAX)通话,并确保第一个收件人与最后一个收件人相同。

我不必加入用于分组的精简的“ JustDate”列,因为MIN / MAX限定了完整日期/时间。

select
       PQ.JustDate,
       PQ.CallerID,
       pl1.RecipientID
    from
        ( select
                callerID,
                convert( date, dateCalled ) JustDate,
                min( DateCalled ) minDateCall,
                max( DateCalled ) maxDateCall
            from
                PhoneLog pl
            group by
                callerID,
                convert( date, dateCalled ) 
            having
                count(*) > 1) PQ
            JOIN PhoneLog pl1
                on PQ.CallerID = pl1.CallerID
                AND PQ.minDateCall = pl1.dateCalled
                JOIN PhoneLog pl2
                    on PQ.CallerID = pl2.CallerID
                    AND PQ.maxDateCall = pl2.dateCalled
                    AND pl1.RecipientID = pl2.RecipientID

答案 1 :(得分:1)

从SQL Server 2019开始,您可以使用first_value()last_value()窗口函数。

SELECT DISTINCT
       x1.callerid,
       x1.fri,
       x1.datecalled
       FROM (SELECT pl1.callerid,
                    pl1.recipientid,
                    convert(date, pl1.datecalled) datecalled,
                    first_value(pl1.recipientid) OVER (PARTITION BY pl1.callerid,
                                                                    convert(date, pl1.datecalled)
                                                       ORDER BY pl1.datecalled
                                                       RANGE BETWEEN UNBOUNDED PRECEDING
                                                                     AND UNBOUNDED FOLLOWING) fri,
                    last_value(pl1.recipientid) OVER (PARTITION BY pl1.callerid,
                                                                  convert(date, pl1.datecalled)
                                                      ORDER BY pl1.datecalled
                                                      RANGE BETWEEN UNBOUNDED PRECEDING
                                                                     AND UNBOUNDED FOLLOWING) lri
                    FROM phonelog pl1) x1
       WHERE x1.fri = x1.lri;

在旧版本中,您可以将关联子查询与TOP 1一起使用。

SELECT DISTINCT
       x1.callerid,
       x1.fri,
       x1.datecalled
       FROM (SELECT pl1.callerid,
                    pl1.recipientid,
                    convert(date, pl1.datecalled) datecalled,
                    (SELECT TOP 1
                            pl2.recipientid
                            FROM phonelog pl2
                            WHERE pl2.callerid = pl1.callerid
                                  AND pl2.datecalled >= convert(date, pl1.datecalled)
                                  AND pl2.datecalled < dateadd(day, 1, convert(date, pl1.datecalled))
                            ORDER BY pl2.datecalled ASC) fri,
                    (SELECT TOP 1
                            pl2.recipientid
                            FROM phonelog pl2
                            WHERE pl2.callerid = pl1.callerid
                                  AND pl2.datecalled >= convert(date, pl1.datecalled)
                                  AND pl2.datecalled < dateadd(day, 1, convert(date, pl1.datecalled))
                            ORDER BY pl2.datecalled DESC) lri
                    FROM phonelog pl1) x1
       WHERE x1.fri = x1.lri;

db<>fiddle

如果您不想返回某人一天只打了一个电话的日志行,这当然意味着当天的第一次和最后一次打给同一个人,则可以使用GROUP BYHAVING count(*) > 1而不是DISTINCT

SELECT x1.callerid,
       x1.fri,
       x1.datecalled
       FROM (...) x1
       WHERE x1.fri = x1.lri
       GROUP BY x1.callerid,
                x1.fri,
                x1.datecalled
       HAVING count(*) > 1;

答案 2 :(得分:1)

您可以使用CTE来计算Callerid每天的第一个和最后一个呼叫,然后自我加入CTE来查找第一个和最后一个呼叫是相同的Recipientid

WITH CTE AS (
  SELECT Callerid, RecipientId, CONVERT(DATE, Datecalled) AS Datecalled,
         ROW_NUMBER() OVER (PARTITION BY Callerid, CONVERT(DATE, Datecalled) ORDER BY Datecalled) AS rna,
         ROW_NUMBER() OVER (PARTITION BY Callerid, CONVERT(DATE, Datecalled) ORDER BY Datecalled DESC) AS rnb  
  FROM phonelog
)
SELECT c1.Callerid, c1.RecipientId, c1.Datecalled
FROM CTE c1
JOIN CTE c2 ON c1.Callerid = c2.Callerid AND c1.Recipientid = c2.Recipientid
WHERE c1.rna = 1 AND c2.rnb = 1

输出:

Callerid    RecipientId     Datecalled
2           5               2019-07-05
2           3               2019-08-01
2           4               2019-08-02

Demo on SQLFiddle

答案 3 :(得分:0)

据我所知,您想选择callerid中每个Recipientid且时间大于1的情况,以确保我们有首次通话最后通话。因此,您只需要将group by的3列与having count(Recipientid) > 1结合起来

 SELECT Callerid, Recipientid, CAST(Datecalled AS DATE) AS Datecalled
 FROM phonelog
 GROUP BY Callerid, Recipientid, CAST(Datecalled AS DATE)
 HAVING COUNT(Recipientid) > 1

Demo on db<>fiddle

答案 4 :(得分:0)

根据我的理解,我们必须对Caller_id和Recipient_id以及Date进行排名。 下面是我的解决方案,适用于这种情况。

with CTE as 
(select *,
row_number() over (partition by callerid, convert(VARCHAR,datecalled,23) order by convert(VARCHAR,datecalled,23)) as first_recipient_id,
row_number() over (partition by receipientid, convert(VARCHAR,datecalled,23) order by convert(VARCHAR,datecalled,23) desc) as last_recipient_id
from activity
)
       
select t.callerid,t.receipientid,CONVERT(VARCHAR,t.datecalled) as DateCalled from CTE t      
where t.first_recipient_id >1 AND t.last_recipient_id>1;

我能够得到的结果:

Result

答案 5 :(得分:0)

我认为我们需要确定一天中呼叫者打出的第一个和最后一个电话,然后将其与当天呼叫者给接收者的第一个和最后一个电话进行比较。下面的代码具有一天中呼叫者进行的firstcall和lastcall。然后,它会找到呼叫者对相应接收者的第一个和最后一个呼叫,然后进行比较。

    SELECT DISTINCT 
            callerid,
    recipientid,
    CONVERT(date,firstcall) 
    FROM
    (
      Select 
        callerid,
        recipientid,
        MIN(dateCalled) OVER(PARTITION BY callerid,CONVERT(date,DateCalled)) as firstcall,
        MAX(DateCalled) OVER(PARTITION BY callerid,CONVERT(date,DateCalled)) as lastcall,
        MIN(DateCalled) OVER(PARTITION BY callerid,recipientid,convert(date,DateCalled)) as recipfirstcall,
        MAX(call_start_time) OVER(PARTITION BY callerid,recipientid,convert(date,DateCalled)) as reciplastcall
    from phonelog
) as A 
where A.firstcall=A.recipfirstcall and A.lastcall=A.reciplastcall

答案 6 :(得分:0)

使用窗口函数很容易

WITH cte AS (
SELECT *, CAST(DateCalled as DATE) DateCalled
,FIRST_VALUE(Recipientid) OVER (PARTITION BY Callerid  ,CAST(DateCalled as date) ORDER BY CAST(DateCalled AS DATE)) f
,LAST_VALUE(Recipientid) OVER (PARTITION BY Callerid  ,CAST(DateCalled as date) ORDER BY CAST(DateCalled AS DATE)) l
FROM phonelog 
)

SELECT DISTINCT Callerid,Recipientid, DateCalled FROM cte 
WHERE  f=l