Полукомплексный совокупный выбор путаницы - PullRequest
1 голос
/ 08 марта 2010

Хорошо, эта проблема немного сложна, так что терпите меня.

У меня есть таблица, полная данных. Одним из столбцов таблицы является 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, что приведет к неправильным результатам (особенно если идентификатор уникален).

Я нашел грязный хак, который будет делать то, что я хочу, но должен быть лучший способ - вот мое текущее решение:

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, если это имеет какое-либо значение)

1 Ответ

2 голосов
/ 08 марта 2010

Не существует действительно «элегантного» способа. Когда у вас есть подобные запросы группы 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

Вы не должны быть слишком расстроены решением, которое вы придумали. Использование временных таблиц никогда не выглядит элегантно, но эффективно; Я не удивлюсь, если ваше оригинальное двухэтапное решение на самом деле быстрее моего одношагового. (вам нужно проверить, чтобы знать наверняка.)

...