呼叫者,其第一个和最后一个呼叫是同一个人



我有一个电话日志表,其中包含有关呼叫者呼叫历史记录的信息。我想找出在某一天第一次和最后一次打电话给同一个人的来电者。

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

另一个dbFiddle选项

首先,我的预查询(PQ 别名(,我每天为给定的客户获取最小和最大通话时间,但也必须确保某人在给定的一天内至少有 2 个电话。 从那以后,我重新加入给定日期该人的第一次 (MIN( 呼叫的电话日志表。 然后,我在同一天再次为同一个人加入最后一次(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

使用窗口功能非常简单

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

从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;

数据库<>小提琴

如果您不想返回某人在一天中只进行了一次调用的日志行,这当然意味着当天的第一个和最后一个调用是同一个人,您可以使用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;

您可以使用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

关于SQLFiddle的演示

据我了解,您希望为每个时间大于 1 的Recipientid选择callerid,以确保我们有第一次调用最后一次调用。所以你只需要group by3 列与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

在数据库<>小提琴上演示

根据我的理解,我们必须Caller_id以及日期一起排名Recipient_id。 以下是我的解决方案,适用于这种情况。

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;

我能够得到的结果:

结果

我认为我们需要确定呼叫者在一天中拨打的第一个和最后一个电话,然后将其与呼叫者当天对收件人的第一个和最后一个电话进行比较。下面的代码有调用者在一天中进行的第一次调用和最后一次调用。然后,它找到呼叫者对相应收件人的第一个和最后一个呼叫,然后进行比较。

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

最新更新