2010-03-08 63 views
1

好吧,这个问题有点复杂,请耐心等待。半复杂集合选择语句混淆

我有一张充满数据的表格。其中一个表列是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上,逻辑上定义了唯一性。

现在,就像我所说的,我想要选择在特定日期(对于每个Person-Store组合)最新条目的所有行。这很容易:

--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)上的正确连接可以实现诀窍,就像自连接或其他东西一样......但您如何使用group by子句做到这一点?我无法找到正确的语法来执行查询。

我很新的SQL,所以很可能我错过了一些明显的东西。有什么建议么?

(以T-SQL的工作,如果它使任何区别)

回答

2

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

这将工作:

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 

你不应该在你想出虽然解决得下来。使用临时表从来没有看起来优雅,但它是高效的;如果您的原始两步解决方案实际上比我的单步解决方案更快,我不会感到惊讶。 (你必须进行测试才能确定。)

+0

感谢您对表现的关注。我尝试了两种方法,而且你是对的 - 临时表方法的速度提高了1秒(总共83和84秒)!但是我会在任何一天(几乎)任何一天对你的解决方案进行简洁的说明...... – 2010-03-08 18:43:31