2010-03-08 3 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 조합에 대해)의 최신 항목 인 모든 행을 선택하려고합니다. 이것은 매우 간단합니다 : dbo.dayof은() 날짜 시간에서 시간 구성 요소를 제거합니다 간단한 함수입니다

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

. 그러나이 작업을 수행하면 나머지 열이 손실됩니다! 다른 열을 단순히 포함 할 수는 없습니다. 왜냐하면 잘못된 결과를 생성하는 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 나에게 정확한 데이터를 얻을 수 있지만, 여기 내 현재의 솔루션입니다 -

나는 내가 원하는 것을 할 것입니다 더러운 해킹을 발견하지만, 더 나은 방법이 있어야합니다 그것을 보라! null 값을 사용하여 테이블을 만든 다음 값을 가져 오기 위해 업데이트를 수행하십시오. 이렇게하는 것이 더 좋은 방법일까요? 처음에 모든 값을 얻을 수있는 단일 문장?

원래의 select (그림 1)에 대한 올바른 조인은 자체 조인 또는 다른 것과 같은 트릭을 수행 할 것이라고 제 믿음입니다.하지만 group by 절을 사용하여 어떻게 할 수 있습니까? 쿼리를 실행하기위한 올바른 구문을 찾을 수 없습니다.

나는 SQL로 새로운 것이므로 분명하지 않은 것 같다. 어떤 제안?

답변

2

에는 정말 "우아한"방법이 없다 (그것은 어떤 차이가 있는지, T-SQL에서 작업)

. 이와 같은 Group Group By 쿼리를 사용하면 하위 쿼리 또는 임시 테이블을 갖게됩니다.

이 작동합니다 :

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 

너무 아래로 당신이 생각 해낸 해결책에해서는 안됩니다. 임시 테이블을 사용하여 결코 보이는 우아한,하지만 그것은 효율적입니다; 원래 2 단계 솔루션이 실제로 내 1 단계 솔루션보다 빠르다면 놀라지 않을 것입니다. (당신이 확실히 알기 위해 테스트해야 할 것입니다.)

+0

성능에 대한 머리를 주셔서 감사합니다. 나는 두 가지 방법으로 시도했고, 당신 말이 맞습니다. 임시 테이블 방법이 1 초 더 빨리 완료되었습니다 (총 83 초 v 84 초)! 하지만 나는 그 부스트 (거의)에 대한 당신의 솔루션의 간결성을 언제든지 취할 것입니다 ... –