2012-01-31 6 views
2

Я полностью переписываю свой вопрос, чтобы упростить его. Извините, если вы прочли предыдущую версию. (Предыдущая версия этого вопроса включала очень сложный пример запроса, который создал отвлечение от того, что мне действительно нужно.) Я использую SQL Express.SQL Sum и Group By для запуска Tally?

У меня есть таблица уроков.

LessonID StudentID StudentName LengthInMinutes 
1   1   Chuck  120 
2   2   George  60 
3   2   George  30 
4   1   Chuck  60 
5   1   Chuck  10 

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

Мне нужно запросить эту таблицу, чтобы получить все строки (или подмножество строк по дате диапазон или студентом), но мне нужен мой запрос, чтобы добавить новый столбец, который мы могли бы назвать PriorLessonMinutes. То есть, сумма всех минут всех уроков для одного и того же ученика на уроках дат PRIOR.

Так что запрос возвратит:

LessonID StudentID StudentName LengthInMinutes PriorLessonMinutes 
1   1   Chuck  120    0 
2   2   George  60    0 
3   2   George  30    60 (The sum Length from row 2 only) 
4   1   Chuck  60    120 (The sum Length from row 1 only) 
5   1   Chuck  10    180 (The sum of Length from rows 1 and 4) 

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

Кроме того, (и это важно), если я извлекаю только подмножество записей (например, в диапазоне дат), PriorLessonMinutes должен быть суммой, которая рассматривает строки, которые НЕ возвращаются.

Моя первая идея состояла в том, чтобы использовать SUM() и GROUP BY Student, но это не так, потому что, если я не ошибаюсь, это будет включать в себя сумму минут для всех строк для каждого ученика, включая строки, которые появляются после строки, которые не имеют отношения к сумме, в которой я нуждаюсь.

ВАРИАНТЫ Я ОТКАЗЫВАЮ: Я мог сканировать все строки в моем коде, который его получает (хотя это заставило бы меня без всякой необходимости извлекать все строки), но это явно неэффективно. Я мог бы также разместить там реальное поле данных и заполнить его, но это также создает проблемы, когда другие записи удаляются или изменяются.

Я не знаю, как написать такой запрос вместе. Любые указания?

ответ

0

Я чувствую, что следующий код будет служить вашей purpose.Check его: -

select Students.StudentID ,Students.First, Students.Last,sum(Lessons.LengthInMinutes)  
    as TotalPriorMinutes from lessons,students 
    where Lessons.StartDateTime < getdate() 
    and Lessons.StudentID = Students.StudentID 
    and StartDateTime >= '20090130 00:00:00' and StartDateTime < '20790101 00:00:00' 
    group by Students.StudentID ,Students.First, Students.Last 
+0

Вы проверили мой код? – Sukanya

+0

Я еще не проверял его, но, пожалуйста, обратите внимание, что, пока вы печатали свой ответ, я полностью переписал свой вопрос. Извини за это. – PaulOTron2000

+0

Хорошо, я проверил его сейчас. Конечно, это относится к моему вопросу, как изначально написанному, в котором было присоединение, а не к тому, что показано выше. (Я могу справиться с проблемой присоединения.) И он включает в себя GetDate, которая является текущей датой, которая не имеет значения, поскольку каждый урок имеет собственное поле даты, поэтому один и тот же запрос должен давать одинаковые результаты независимо от того, когда он выполняется. Однако, спасибо. – PaulOTron2000

1

Это отличная возможность использовать WINDOWED агрегатами. Фокус в том, что вам нужен SQL Server Экспресс. Если вы можете получить его, то это запрос вы ищете:

select *, 
    sum(LengthInMinutes) 
    over (partition by StudentId order by LessonId 
     rows between unbounded preceding and 1 preceding) 
    as PriorLessonMinutes 
from Lessons 

Обратите внимание, что она возвращает значение NULL вместо 0s (нули). Если вы настаиваете на нулях, используйте функцию COALESCE, чтобы превратить NULL в нули.

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

select * from 
(
    select *, 
    sum(LengthInMinutes) 
     over (partition by StudentId order by LessonId 
     rows between unbounded preceding and 1 preceding) 
     as PriorLessonMinutes 
    from Lessons 
) as NestedLessons 
where LessonId > 3 -- this is an example of a filter 

Таким образом, фильтр применяется после завершения агрегации.

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

+0

Очень интересно. Пока это верхняя часть, и я могу нажать кнопку «Проверить ответ» позже, если я смогу заставить ее работать. (В настоящее время у меня нет SQL Server 2012 Express, это только кандидат на выпуск, который касается меня.) Также я не знаком с этим синтаксисом, поэтому перед обновлением я хотел бы задать вопрос: будет ли «несвязанный предыдущий», заставить его делать сумму всех строк, включая те, которые НЕ возвращаются? См. Мой абзац, начинающийся с: «Далее (и это важно) ...« Это предостережение может быть моментом. – PaulOTron2000

+0

Запуск события для SQL Server 2012 запланирован на 7 марта. Окончательные бит SQL Server 2012 Express должны быть доступны примерно в это время. См. Http://sqlserverlaunch.com/WW/Home. –