【问题标题】:SQL: Filter records based on record creation date and other criteriaSQL:根据记录创建日期和其他条件过滤记录
【发布时间】:2017-04-06 09:50:12
【问题描述】:

我正在努力寻找更好的解决方案来从我的用户呼叫数据表中选择唯一记录。 我的表结构如下:

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

此表中有多个具有不同且相同 ID 的条目。我想检查 [FromPhone] 和 [ToPhone] 在过去 3 个月内是否存在多次,如果是,我想根据 [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

【问题讨论】:

  • 我们显然无法理解您的请求。您能否给我们:(a) UserCallData 表的“创建表”脚本,(b) 一些示例数据(如有必要,匿名),以及 (c) 使用该示例数据作为输入时的预期输出。数据应包含说明您希望如何处理所有案例的行(因此,至少,有些在过去三个月内,有些则不是)。

标签: sql sql-server


【解决方案1】:

尝试使用 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 

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

【讨论】:

  • 感谢您回答我的问题!我尝试了您的解决方案,但我需要通过选择第一条记录将这些多次出现分组为一个记录,并将出现次数计为 TotalCallCount 并对 totalCallDuration 求和。此外,上述查询仅返回最近 3 个月的数据。
  • 谢谢!这似乎工作。当发现多次出现时,此查询现在返回唯一记录。现在,我如何引入不属于上述条件的其他记录(没有多次出现)?
  • 我不明白。您想在一个结果中查看所有具有计数和总和的唯一记录吗?
  • 尝试评论/删除 cte_totals 中的 WHERE 块。
  • 非常感谢ventik 和@Steve Lovell。它现在正在工作。让我做一些测试,如果我有任何问题,请回复您。
【解决方案2】:

我不完全确定我是否理解了这个问题,但如果我有以下可能是您想要的(或者是一个有用的起点):

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) 值(与其他所有行相同,但避免需要额外的“组” by" 条款会干扰其他情况)。在他们不同意的地方,我已经返回"* something"

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

【讨论】:

  • 根据您对 ventik 的 cmets,您可能希望删除 where 子句并在 GROUP BY 中添加以下内容:group by case when ucd.CreationDate >= DATEADD(MONTH, -3, GETDATE()) then null else ucd.ID end)。这假定 ID 唯一标识表中的行。如果没有,您将需要一些可以做的事情。如果表中没有此类可用的内容,您可以使用newid()
猜你喜欢
  • 1970-01-01
  • 2013-06-23
  • 2021-11-10
  • 1970-01-01
  • 2015-11-05
  • 2011-07-26
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多