代码之家  ›  专栏  ›  技术社区  ›  Ian Henry

半复杂聚合select语句混淆

  •  1
  • Ian Henry  · 技术社区  · 15 年前

    好吧,这个问题有点复杂,请你放心。

    我有一张数据表。其中一个表列是EntryDate。每天可以有多个条目。但是,我要选择在其各自的日期中是最新条目的所有行,并且要选择所述表的所有列。

    其中一列是一个唯一的标识符列,但它不是主键(我不知道它为什么存在;这是一个非常古老的系统)。出于演示目的,假设表如下所示:

    create table ExampleTable (
        ID int identity(1,1) not null,
        PersonID int not null,
        StoreID int not null,
        Data1 int not null,
        Data2 int not null,
        EntryDate datetime not null
    )
    

    主键在personid和storeid上,后者在逻辑上定义了唯一性。

    现在,如我所说,我要选择在特定日期(对于每个人存储组合)的所有最新条目。这很容易:

    --Figure 1
    select PersonID, StoreID, max(EntryDate)
    from ExampleTable
    group by PersonID, StoreID, dbo.dayof(EntryDate)
    

    其中dbo.dayof()是一个简单的函数,它从日期时间中除去时间组件。但是,这样做会丢失其余的列!我不能简单地包括其他列,因为那样我就必须 group by 它们会产生错误的结果(尤其是ID是唯一的)。

    我发现了一个可以做我想做的事情的肮脏黑客,但一定有更好的方法——这是我目前的解决方案:

    select
        cast(null as int) as ID,
        PersonID,
        StoreID,
        cast(null as int) as Data1,
        cast(null as int) as Data2,
        max(EntryDate) as EntryDate
    into #StagingTable
    from ExampleTable
    group by PersonID, StoreID, dbo.dayof(EntryDate)
    
    update Target set
        ID = Source.ID,
        Data1 = Source.Data1,
        Data2 = Source.Data2,
    from #StagingTable as Target
    inner join ExampleTable as Source
        on Source.PersonID = Target.PersonID
       and Source.StoreID = Target.StoreID
       and Source.EntryDate = Target.EntryDate
    

    这使我得到了正确的数据 #StagingTable 但是,好吧,看看它!创建一个带有空值的表,然后进行更新以返回值——确实有更好的方法可以做到这一点吗?一个能让我第一次得到所有值的语句?

    我相信正确的加入 select (图1)会做一些技巧,比如一个自连接或者其他什么…但是你是怎么做到的 分组依据 条款?我找不到正确的语法来执行查询。

    我对SQL很陌生,所以很可能我遗漏了一些明显的东西。有什么建议吗?

    (在T-SQL中工作,如果有任何不同)

    1 回复  |  直到 15 年前
        1
  •  2
  •   Patrick Karcher    15 年前

    没有真正的“优雅”方式。当您有这样的分组查询时,您将拥有子查询或临时表。

    这将起作用:

    Select ID, A.PersonID, A.StoreID, Data1, Data2, A.EntryDate
    From ExampleTable As A
    Inner Join
        (select PersonID, StoreID, max(EntryDate) As EntryDate
        from ExampleTable
        group by PersonID, StoreID, dbo.dayof(EntryDate)) As B
      On ExampleTable.PersonID = B.PersonID 
        And ExampleTable.StoreID = B.StoreID 
        And ExampleTable.EntryDate = B.EntryDate
    

    不过,你不应该对你提出的解决方案过于悲观。从不使用临时表 优雅,但它是有效的;如果您最初的两步解决方案实际上比我的一步解决方案快,我不会感到惊讶。(你必须测试才能确定。)