Rambler's Top100
Форум: MS ACCESSVBVBA MS OfficeMS SQL server
Новые сообщения: 0000

Форум: MS ACCESS

Вопросы связанные с MS ACCESS

Обновить визитку
Участники «Online»
Все участники

 
 

Доброго времени суток, Посетитель!

вид форума:
Линейный форум Структурный форум

тема: запрос с группировкой
 
 автор: dmsrv803   (05.04.2011 в 11:53)   личное сообщение
 
 

Есть запрос Query1:

SELECT Dogovor.Dogovor_Id, Status_Id, DateStatusChanged FROM Dogovor INNER JOIN Status ON Dogovor.Dogovor_Id = Status.Dogovor_Id ORDER BY DateStatusChanged;

Данный запрос возвращает набор данных, который содержит информацию о статусе договоров. Причем, если договор имееет несколько статусов, то последним в наборе оказывается статус, имееющий наибольшее значение в поле DateStatusChanged.

Дальше мне необходимо с помощью другого запроса получить последний (действующий) статус договора. Т.е. найти статус договора с наибольшим значением поля DateStatusChanged.

SELECT Dogovor_Id, Last(Status_ID) As LastStatus_Id, Last(DataStatusChanged) As LastData FROM Query1 GROUP BY Dogovor_Id;

Но к моему огорчению запрос отрабатывает не корректно. До тех пор, пока наибольшему значению поля Status_Id соответствует поле DataStatusChanged с наибольшем значением - все в порядке, но как только например изменить дату статуса таким образом, что она станет меньше даты предыдущего статуса, то запрос возвращает дату одного статуса и Id другого.
Подскажите, как мне составит ь запрос, чтобы он отрабатывал корректно?

  Ответить  
 
 автор: ser60   (05.04.2011 в 12:04)   личное сообщение
 
 

нужно групировать по дате Last

  Ответить  
 
 автор: dmsrv803   (05.04.2011 в 12:15)   личное сообщение
10 Кб.
 
 

вот небольшой примерчик - поправте если не трудно.
Если во втором запросе применить MAX(DateSatatusChanged) As Max_Date и убрать Last(Status_Id), с помощью еще одного запроса SELECT Dogovor_Id, Max_Date, Status_Id FROM Query2 INNER JOIN Status ON Query2.Dogovor_Id = Status.Dogovor_Id AND Query2.Max_Date = Status.DateStatusChanged;
- то вроде все получается.

  Ответить  
 
 автор: snipe   (05.04.2011 в 12:42)   личное сообщение
 
 

а так
SELECT Запрос1.Dogovor_Id, Last(Запрос1.DataStatusChanged) AS [Last-DataStatusChanged], Max(Запрос1.Status_Id) AS [Max-Status_Id]
FROM Запрос1
GROUP BY Запрос1.Dogovor_Id;

  Ответить  
 
 автор: dmsrv803   (05.04.2011 в 12:59)   личное сообщение
 
 

Как показали мои многочисленные эксперименты с Last и Max - они в запросе друг с другом вообще никак не связаны (как скорей всего и другие функции агрегированния) и единственное что их объединяет это то что они возвращают только одно (естественно) значение. Удивительно то, что результат работы Last не зависит от порядка вывода значений в первом запросе отсортированного по дате.

  Ответить  
 
 автор: Stanislav   (05.04.2011 в 12:47)   личное сообщение
 
 

В твоем примере все верно. А можно и так:

SELECT Status.Dogovor_Id, Max(Status.DataStatusChanged) AS MaxOfDataStatusChanged, Max(Status.Status_Id) AS MaxOfStatus_Id
FROM Status
GROUP BY Status.Dogovor_Id;

Здесь порядок следования полей Max(Status.DataStatusChanged) AS MaxOfDataStatusChanged, Max(Status.Status_Id) AS MaxOfStatus_Id определяет порядок сортировки. Т.е. сначала он отберет Max(Status.DataStatusChanged) AS MaxOfDataStatusChanged, а потом среди них Max(Status.Status_Id) AS MaxOfStatus_Id
В твоем примере ты добился того же самого, двумя последовательными запросами.
Оба способа приемлемы. Просто если тебе первый промежуточный запрос, отбирающий договоры по макс. дате, нигде больше не нужен, то проще сделать одним запросом.

  Ответить  
 
 автор: dmsrv803   (05.04.2011 в 13:05)   личное сообщение
16 Кб.
 
 

Не соглашусь. Здесь мы получим наибольшее значение для поля DataStatusChanged и нибольшее значение для поля Status_Id и никакой гарантии что эти значения будут соответствовать искомому результату.

  Ответить  
 
 автор: Анатолий (Киев)   (05.04.2011 в 16:08)   личное сообщение
 
 

Где-то так:
SELECT T1.Dogovor_Id, T1.DataStatusChanged As LastData, Max(T2.Status_ID) AS LastStatus_Id
FROM Query1 AS T2 INNER JOIN (SELECT T1.Dogovor_Id, Max(T1.DataStatusChanged) AS DataStatusChanged
FROM Query1 AS T1 GROUP BY T1.Dogovor_Id) AS T1 
ON (T2.DataStatusChanged = T1.DataStatusChanged) AND (T2.Dogovor_Id = T1.Dogovor_Id)
GROUP BY T1.Dogovor_Id, T1.DataStatusChanged;

  Ответить  
 
 автор: dmsrv803   (05.04.2011 в 16:38)   личное сообщение
 
 

мысль интерсная, но вот насчет 'GROUP BY T1.Dogovor_Id, T1.DataStatusChanged' я что-то сомневаюсь. Думаю эта группировка лишняя т.к. запрос
(SELECT T1.Dogovor_Id, Max(T1.DataStatusChanged) AS DataStatusChanged
FROM Query1 AS T1 GROUP BY T1.Dogovor_Id)
- однозначно определяет id договора и наибольшую дату по которым возможно определить Status_ID.

  Ответить  
 
 автор: Анатолий (Киев)   (05.04.2011 в 19:17)   личное сообщение
 
 

Согласен, в данном случае можно и без группировки, но тогда для T1.Dogovor_Id, T1.DataStatusChanged нужно применить какую-нибудь статистическую функцию, например First.

  Ответить  
 
 автор: dmsrv803   (07.04.2011 в 13:22)   личное сообщение
 
 

т.е. это на тот случай если в течении одного дня статус менялся дважды?

  Ответить  
 
 автор: Анатолий (Киев)   (07.04.2011 в 16:15)   личное сообщение
 
 

Нет.
Если в запросе к одному полю применена статистическая функция или группировка, то и к остальным выводимым полям нужно применить подобное.

Вы бы, чем вопросы задавать, сначала попробовали свой вариант.

  Ответить  
 
 автор: shanemac51   (07.04.2011 в 16:25)   личное сообщение
 
 

возможно так


SELECT (T1.Dogovor_Id & '=' &  T1.DataStatusChanged) As LastIdData, Max(T2.Status_ID) AS LastStatus_Id
FROM Query1 AS T2 INNER JOIN (SELECT T1.Dogovor_Id, Max(T1.DataStatusChanged) AS DataStatusChanged
FROM Query1 AS T1 GROUP BY T1.Dogovor_Id) AS T1 
ON (T2.DataStatusChanged = T1.DataStatusChanged) AND (T2.Dogovor_Id = T1.Dogovor_Id)
GROUP BY T1.Dogovor_Id & '=' & T1.DataStatusChanged;

затем выбрать из таблицы согласно T1.Dogovor_Id & '=' & T1.DataStatusChanged

  Ответить  
HiProg.com - Технологии программирования
Rambler's Top100 TopList