2017-04-06 93 views
0

我很努力地找到更好的解决方案,从我的用户调用数据表中选择唯一记录。 我的表结构如下:SQL:根据记录创建日期和其他条件筛选记录

SELECT [MarketName], 
     [WebsiteName] , 
     [ID] , 
     [UserID], 
     [CreationDate], 
     [CallDuration], 
     [FromPhone] , 
     [ToPhone], 
     [IsAnswered], 
     [Source] 
FROM [dbo].[UserCallData] 

有此表中的多个条目与不同和相同的ID。我想在最近3个月内检查[FromPhone]和[ToPhone]是否存在多次,如果是,我想根据[CreationDate]选择所有列的第一条记录,将出现次数计为TotalCallCount,并将totalCallDuration作为单个记录。如果[FromPhone]和[ToPhone]没有多次出现,我想选择所有列。我已经能够提出如下的部分查询。但是,如果没有包含在group by子句中,这不会返回所有列,也不会满足我的整个条件。任何帮助,将不胜感激。

select [FromPhone], 
     MIN([CreationDate]), 
     [ToPhone], 
     marketname, 
     count(*) as TotalCallCount , 
     sum(CallDuration) as TotalCallDuration 
from [dbo].[UserCallData] 
where [CreationDate] >= DATEADD(MONTH, -3, GETDATE()) 
group by [FromPhone],[ToPhone], marketname 
having count([FromPhone]) > 1 and count([ToPhone]) >1 
+0

我们显然在理解您的请求时遇到问题。 (a)UserCallData表格的“create table”脚本,(b)一些示例数据(如果必要的话,匿名),以及(c)使用该示例数据作为输入时的预期输出。数据应包含说明您希望如何处理所有案例的行(最低限度有些在最近三个月内,有些则没有)。 –

回答

0

尝试使用ROW_NUMBER()

;with cte as 
(
    select *, ROW_NUMBER() OVER(PARTITION BY FromPhone, ToPhone ORDER BY CreationDate) as RN 
    from UserCallData 
    where CreationDate >= DATEADD(MONTH, -3, GETDATE()) 
), 
cte_totals as 
(
    select C1.FromPhone, C1.ToPhone, COUNT(*) as TotalCallCount, SUM(CallDuration) as TotalCallDuration 
    from cte C1 
    where exists(select * from cte C2 where C1.FromPhone = C2.FromPhone and C1.ToPhone = C2.ToPhone and C2.RN > 1) 
    group by C1.FromPhone, C1.ToPhone 
) 
select C1.*, TotalCallCount, TotalCallDuration 
from cte C1 
    inner join cte_totals C2 on C1.FromPhone = C2.FromPhone and C1.ToPhone = C2.ToPhone 
where C1.RN = 1 

我写的查询就在这里,所以它可以有一些错误或输入错误,但主要的想法可能是清楚的。

+0

感谢您回答我的问题!我尝试了你的解决方案,但我需要通过挑选第一条记录将这些多个事件分组成一条记录,并将出现次数计数为TotalCallCount并总计totalCallDuration。此外,上述查询仅返回最近3个月的数据。 – user7617078

+0

谢谢!这似乎是工作。此查询现在会在找到多个匹配项时返回唯一记录。现在,我如何引入其他不符合上述标准的记录(如果没有多次出现)? – user7617078

+0

我不明白。你想在一个结果中看到所有具有计数和总和的独特记录吗? – ventik

0

我不能完全肯定我理解的问题,但如果我有以下可能是你想要什么(或者是一个有用的起点):

SELECT 
     ucd.FromPhone, 
     min(ucd.CreationDate) as MinCreationDate, 
     ucd.ToPhone, 
     ucd.MarketName, 
     count(*) as TotalCallCount, 
     sum(ucd.CallDuration) as TotalCallDuration, 
     case 
      when min(ucd.WebsiteName) = max(ucd.WebsiteName) then min(ucd.WebsiteName) 
      else '* Various' 
     end as WebsiteName, 
     case 
      when min(ucd.ID) = max(ucd.ID) then min(ucd.ID) 
      else '* Various' 
     end as ID, 
     case 
      when min(ucd.UserID) = max(ucd.UserID) then min(ucd.UserID) 
      else '* Various' 
     end as UserID, 
     case 
      when min(ucd.IsAnswered) = max(ucd.IsAnswered) then min(ucd.IsAnswered) 
      else '* Some' 
     end as IsAnswered, 
     case 
      when min(ucd.Source) = max(ucd.Source) then min(ucd.Source) 
      else '* Various' 
     end as Source 
FROM 
    dbo.UserCallData ucd 
WHERE 
    ucd.CreationDate >= DATEADD(MONTH, -3, GETDATE()) 
GROUP BY 
    ucd.FromPhone, 
    ucd.ToPhone, 
    ucd.MarketName 

当我们正在崩溃行在一起,如果所有的行在一个给定的列上都是一致的(所以min(Field) = max(Field)),我返回min(Field)值(这与所有其他值相同,但避免了需要额外的“group by”子句会干扰其他情况的问题)。他们并不都同意,我已经返回"* something"

该代码假定所有列都是文本类型列(您没有说过),则可能会出现转换错误。它还假定这些字段都不是null。如果这些假设不正确,您/我们可以修改代码。如果你无法为自己做到这一点,让我知道问题,我会很乐意尽我所能。

+0

根据您对ventik的评论,您可能希望删除where子句并在GROUP BY中添加以下内容:ucd.CreationDate> = DATEADD(MONTH,-3,GETDATE())时,按组情况添加以下内容,然后返回null else ucd。 ID结束)'。这假定该ID唯一标识表中的行。如果没有,你需要做的事情。如果表中没有这种可用的东西,你可以使用'newid()'。 –