Форум программистов, компьютерный форум, киберфорум
Delphi: Базы данных
Войти
Регистрация
Восстановить пароль
Блоги Сообщество Поиск Заказать работу  
 
Рейтинг 4.66/29: Рейтинг темы: голосов - 29, средняя оценка - 4.66
8 / 1 / 0
Регистрация: 15.12.2012
Сообщений: 8

Среднее арифметическое строк нескольких столбцов

04.01.2013, 00:13. Показов 5453. Ответов 14
Метки нет (Все метки)

Студворк — интернет-сервис помощи студентам
Добрый день! Пожалуйста, помогите советом - я в отчаянии. Последние полтора месяца не вставая пишу программу на диплом. До сдачи осталось чуть больше недели. Программа работает с db файлами Paradox через dbgrideh. Почти все готово - прога сама создает таблицы через sql-запрос, потом её можно открыть и начать наполнять, осталось "только" объяснить программе, как считать средний балл.

Таблицы имеют примерно следующую структуру (только имена на английском и предметов больше):
Студент | Предм1_Т1 | Предм1_Т2 | Предм_Т3 | Предм1_СрБалл
Иванов 5 3 3 ?
Петров 4 5 4 ?
Сидоров 5 5 4 ?

Пробовал всяко - в итоге остановился на мысли, что нужно делать через SQL. Пишу следующее:
Delphi
1
2
3
4
5
6
7
8
9
10
11
  Query1.DatabaseName:= Table1.DatabaseName; //имя БД меняется, поэтому так
  Table1.Edit;
  Table1.Post; //Сохраняем изменения в оценочной ведомости перед подсчетом
  Table1.Edit;
  Query1.Close;
  Query1.SQL.Clear;
  Query1.SQL.Text:='select  Предм1_Т1+Предм1_Т2+Предм_Т3 from '''+table1.TableName+''''; //имена таблицы тоже меняются
  Query1.Open;
 
  Predm1_SrBall:=Query1.Fields[0].asFloat/3; //типа делю сумму на количество предметов
  DBGridEh1.Columns[22].Field.Value :=Predm1_SrBall; //здесь по сути должен средними баллами наполняться столбец 22 (Предм1_СрБалл)
В итоге получается так, что средний балл высчитывается только для первого студента, а ячейки остальных остаются пустыми. Бьюсь над этим уже три дня - в голове каша. Где-то прочитал, что такое на SQL вообще невозможно, но очень надеюсь, что все-таки это сделать реально.
Знатоки, помогите пожалуйста.
0
IT_Exp
Эксперт
34794 / 4073 / 2104
Регистрация: 17.06.2006
Сообщений: 32,602
Блог
04.01.2013, 00:13
Ответы с готовыми решениями:

Изменение запроса в зависимости от выбранных строк в нескольких DbGrid (в SQL получить значения из нескольких DataSet)
Здравствуйте. Есть таблицы и компоненты: Tbl_authors – Таблица авторов. С ней связаны компоненты: - ADOTable_authors, -...

среднее арифметическое строк и столбцов
Отзовитесь, ЭКСПЕРТЫ!!! Вот условие задачи: сред. арифм. строк и столбцов. Если макс. сред. арифм. строк больше сред. арифм. столбцов...

Среднее арифметическое строк и столбцов
Необходимо найти среднее арифметическое строк и столбцов элементов матрицы B=(bij)m*n. Если максимальное среднее арифметическое строк...

14
1076 / 989 / 340
Регистрация: 07.08.2012
Сообщений: 2,790
04.01.2013, 00:53
Есть простой способ показать рассчитанные значения в DBGrid (в DbGridEh тоже).
В процедуре обработки события OnDrawColumnCell.
Для этого в списке колонок DBGridEh создается еще одна колонка, в которой будет показан средний балл.
Delphi
1
2
3
4
5
6
7
8
9
10
procedure TForm1.DBGridEh1DrawColumnCell(Sender: TObject;
    const Rect: TRect; DataCol: Integer; Column: TColumn; State: TGridDrawState);
var
  S : Double;
begin
  if Column.Index = 6 then begin //номер колонки, куда выводится значение. Это номер в списке колонок.
    S := (Table1['Предм1_Т1'] + Table1['Предм1_Т2'] + Table1['Предм_Т3']) / 3;
    DBGridEh1.Canvas.TextOut(Rect.Left+2, Rect.Top+2, Format('%3.1f', [S]));
  end;
end;
При условии, что Table1 связана с DBGridEh1.
2
8 / 1 / 0
Регистрация: 15.12.2012
Сообщений: 8
04.01.2013, 13:43  [ТС]
Скандербег, Вы мой кумир. Пребываю в шоке. Столько бился, но благодаря Вам все получилось за пару минут. Спасибо, от души.

Добавлено через 21 минуту
Осталось только поставить проверку на пустоту ячеек. Если я правильно понимаю - нужно до первого If сделать что-то типа этого:
Delphi
1
2
3
4
5
KolPredm:=8; //переменная типа Integer, с количеством оценок по предмету
if Table1['Предм1_Т1']= Null then begin
Table1['Предм1_Т1']:=0;
KolPredm:=KolPredm-1;
end;
Так работает, но тогда в пустых ячейках появляются нули. Может быть есть способ автоматического обхода пустых ячеек?
0
1076 / 989 / 340
Регистрация: 07.08.2012
Сообщений: 2,790
04.01.2013, 14:45
Насчет проверки совершенно верно.
Можно воспользоваться (как альтернатива) функцией VarIsNull (объявлена в модуле Variants):
Delphi
1
2
3
  if VarIsNull(Table1['Предм1_Т1']) then begin
  ...
  end;
А что нули мешают?
1
8 / 1 / 0
Регистрация: 15.12.2012
Сообщений: 8
04.01.2013, 15:05  [ТС]
Скандербег, спасибо, учту . Нули не мешают в принципе, просто без них немного нагляднее. Программа, которую дописываю на диплом в дальнейшем буду внедрять на своей работе. Хочу "убить" таким образом сразу двух зайцев. На данный момент методический состав делает все руками в кривых табличках в Excel'е и хочется, чтобы программа не только облегчала работу автоматическим выводом всего и вся, но и выглядела не хуже, чем эти таблички . В принципе, потом можно ввести обратную проверку на нули и очистить их... сейчас буду смотреть, как это скажется на быстродействии. Ещё раз спасибо.
0
8 / 1 / 0
Регистрация: 15.12.2012
Сообщений: 8
05.01.2013, 20:01  [ТС]
Все-таки добился того, чтобы все считалось без вставки нулей в пустые ячейки. Очень надеюсь, что это поможет таким же нубам, как я .

Сначала в разделе описания переменных прописываем наши переменные типа Integer:
Delphi
1
2
var
  Предм11, Предм12, Предм13: Integer;
Затем у DBGrid (DBgridEh) щелкаем по Event'у OnDrawColumnCell и вставляем такой код:

Delphi
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
procedure TForm2.DBGridEh1DrawColumnCell(Sender: TObject; const Rect: TRect;
  DataCol: Integer; Column: TColumnEh; State: TGridDrawState);
begin
KolPredm:=3; //общее количество оценок по предмету (на него делим общую сумму)
 
if Table1['Предм1_Т1']= Null then begin //если ячейка пустая, то
Предм11:=0;                         //присваиваем 0 переменной Предм1_Т1
KolPredm:=KolPredm-1; //и вычитаем из общего количества оценок единицу
end else Предм11:= Table1['Предм1_Т1']; //в противном случае присваиваем переменной Предм1_Т1 значение ячейки
 
//далее аналогично
 
if Table1['Предм1_Т2']= Null then begin
Предм12:=0;
KolPredm:=KolPredm-1; end else Предм12:= Table1['Предм1_Т2'];
 
if Table1['Предм1_Т3']= Null then begin
Предм13:=0;
KolPredm:=KolPredm-1; end else Предм13:= Table1['Предм1_Т3'];
 
  if Column.Index = 22 then begin //Здесь 22 - номер колонки, куда будет выводится итоговое значение типа Double.
    S := (Предм11+ Предм12+ Предм13) / KolPredm; //складываем наши переменные и делим на общее число оценок
    DBGridEh1.Canvas.TextOut(Rect.Left+2, Rect.Top+2, Format('%3.1f', [S]));
    end;
Добавлено через 53 минуты
Да, и обязательно нужно вставить проверку деления на 0. Только что ломал голову, почему прога перестала считать значения. Еслу у кого-то из студентов вообще нет оценок по предмету, получается, что все ячейки пустые и при каждом вычитании единицы из общего количества оценок - это количество оценок становится равным нулю. Поэтому перед последним IF'ом нужно вставить:
Delphi
1
if KolPredm=0 then KolPredm:=1;
Получается, что сумма общих оценок равна нулю, а общему количеству оценок, которое в этом случае тоже равно нулю присваивается единица и получается 0/1=0.
1
1076 / 989 / 340
Регистрация: 07.08.2012
Сообщений: 2,790
05.01.2013, 20:56
Слишком много лишних телодвижений. Но они не так критичны на современных компах. Гораздо неприятнее другое.
Код этой процедуры выполняется всякий раз когда гриде нужно прорисовать ЛЮБУЮ свою ячейку.
Это приводит к тому, что все вычисления, размещенные в этой процедуре, делаются постоянно, даже тогда, когда
этого делать не нужно (вычисления среднего балла требует только одна колонка).
При большом размере гриды такой "неряшливый" алгоритм может привести к тому, что грида будет постоянно "дергаться", при попытках прорисовки.
Delphi
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
procedure TForm2.DBGridEh1DrawColumnCell(Sender: TObject; const Rect: TRect;
      DataCol: Integer; Column: TColumnEh; State: TGridDrawState);
var
  KolPredm : Integer; //общее количество оценок по предмету (на него делим общую сумму)
  S : double;  //эти переменные начинают и заканчивают жизнь локально, не загромождая память
begin
  if Column.Index = 22 then begin //Здесь 22 - номер колонки, куда будет выводится итоговое значение
    S := 0; KolPredm := 0;
    if Table1['Предм1_Т1'] <> Null then begin //если ячейка не пустая, то...
      S := S + Table1['Предм1_Т1'];           //накапливаем сумму баллов
      Inc(KolPredm);
    end; 
 
      //далее аналогично
    if Table1['Предм1_Т2'] <> Null then begin 
      S := S + Table1['Предм1_Т2'];
      Inc(KolPredm);
    end; 
    if Table1['Предм1_Т3'] <> Null then begin
      S := S + Table1['Предм1_Т3'];
      Inc(KolPredm);
    end; 
    if KolPredm > 0 then begin //если средняя есть, то выводим, если нет, то в ячейке будет пусто
      S := S / KolPredm; //делим на общее число оценок
      DBGridEh1.Canvas.TextOut(Rect.Left+2, Rect.Top+2, Format('%3.1f', [S]));
    end;
  end;
  ...
2
8 / 1 / 0
Регистрация: 15.12.2012
Сообщений: 8
05.01.2013, 22:23  [ТС]
Скандербег, что могу сказать... очень круто. Надеюсь, что и я со временем научусь мыслить более обширно. Логически представляю, что и как примерно должно выглядеть, но опыта практически ноль . Спасибо, Вы в очередной раз сохранили кучу моего времени (которое уже практически на исходе).

Добавлено через 48 минут
Скандербег, взял за основу Вашу мысль и переписал код таким образом:
Delphi
1
2
3
4
5
6
7
8
9
10
  if Column.Index = 22 then begin //Здесь 22 - номер колонки, куда будет выводится итоговое значение
    S := 0; KolPredm:= 3;
    for i := 1 to KolPredm do
    if Table1['Предм1_Т'+IntToStr(i)] <> Null then  //если ячейка не пустая, то...
      S := S + Table1['Предм1_Т'+IntToStr(i)]        //накапливаем сумму баллов
      else  Dec(KolPredm);          //в противном случае уменьшаем общее число оценок на 1
   if S > 0 then begin //если средняя есть, то выводим, если нет, то в ячейке будет пусто
      S := S / KolPredm; //делим на общее число оценок
     DBGridEh1.Canvas.TextOut(Rect.Left+2, Rect.Top+2, Format('%3.1f', [S]));
   end;
Вроде все считается правильно. Если брать самый большой предмет (по некоторым до 12 оценок), то по объему кода получается большой выигрыш, но не скажется ли это на скорости?
0
1076 / 989 / 340
Регистрация: 07.08.2012
Сообщений: 2,790
05.01.2013, 22:42
то по объему кода получается большой выигрыш, но не скажется ли это на скорости?
"Изобретение" по сокращению кода замечательное. Такая креативность заслуживает одобрения. Так и надо.
А о снижении скорости прорисовки и при максимальном количестве предметов можно не беспокоится.
1
8 / 1 / 0
Регистрация: 15.12.2012
Сообщений: 8
06.01.2013, 01:11  [ТС]
Спасибо, будем стараться ))). Никак не могу понять, как посчитать общий средний балл. Пытался складывать все уже полученные средние баллы с аналогичной проверкой на пустоту ячейки, но значение не считается, да и вряд ли итоговый результат можно было бы назвать достоверным, так как все полученные средние баллы были округлены до 1 знака после запятой. Создал для каждого предмета переменную "ИмяПредмета_СреднийБалл" типа Double и присваивал ей значение 'S' после просчета среднего арифметического соответствующего предмета. После этого в самой последней колонке, куда выводится Итоговый средний балл прописал:
"ИмяПредмета1_СреднийБалл" + "ИмяПредмета2_СреднийБалл" + ... / количество средних баллов.
Думал, что будет считать, однако получаю либо ноль, либо огромное число.
0
1085 / 571 / 79
Регистрация: 07.04.2011
Сообщений: 971
Записей в блоге: 2
06.01.2013, 05:15
Почему все таки не использовать запросы?
Так получаем среднее значение
T-SQL
1
2
SELECT (Предм11+Предм12+Предм_Т3)/3 AS Средний_бал
FROM твоя_таблица
Так, общий средний бал
T-SQL
1
2
3
SELECT AVG(Средний_бал)
FROM  (SELECT (Предм11+Предм12+Предм_Т3)/3 AS Средний_бал
           FROM твоя_таблица) AS общий_средний_бал
1
1076 / 989 / 340
Регистрация: 07.08.2012
Сообщений: 2,790
06.01.2013, 09:25
Пытался складывать все уже полученные средние баллы с аналогичной проверкой на пустоту ячейки, но значение не считается, да и вряд ли итоговый результат можно было бы назвать достоверным, так как все полученные средние баллы были округлены до 1 знака после запятой.
Значение ср. балла в природе существует до выхода программы из процедуры где он считается. Затем он только показывается в ячейке гриды.
Поэтому и об округлении здесь говорить бессмысленно, т.к использовать его уже невозможно.
Создал для каждого предмета переменную "ИмяПредмета_СреднийБалл" типа Double и присваивал ей значение 'S' после просчета среднего арифметического соответствующего предмета. ...
Это, вроде, лучше. Хотя, хранить рассчитанные средние в глобальных переменных не самый разумный способ. Оттого и непредсказуемость результата, видимо.
Не видя реализации сказать ничего нельзя.

Если BDE поддерживает SQL запросы, то можно прислушаться к рекомендации antikiler_'а.

Если же нет, то расчет общего среднего мало чем отличается от "частного" среднего. Отличие только в том, что нужные для этого расчета поля используются, в том числе и из других строк-записей. Не надо бояться громоздких вычислений, если они происходят в памяти.
Но без знания структуры БД и проекта, все же, непонятно чего советовать.
1
 Аватар для taras atavin
4226 / 1796 / 211
Регистрация: 24.11.2009
Сообщений: 27,562
06.01.2013, 09:32
PC_USER, столбцы из строк не состоят, они состоят из ячеек.
0
8 / 1 / 0
Регистрация: 15.12.2012
Сообщений: 8
06.01.2013, 14:17  [ТС]
antikiler_, я уже пробовал так - результат считался, но только для первой ячейки, да и делитель даже по одному предмету может отличаться для каждого студента (слушателя). В данном случае способ, предложенный
Скандербег - просто находка.

Скандербег, сегодня проснулся и понял, что нагородил лишнего - сутки, проведенные за компом сказываются на соображалке . Сделал все по-другому - добавил в базу по дополнительному скрытому столбцу для каждого предмета, каждому из которых присваивается соответствующее значение 'S'. В итоговый средний балл прописал все как обычно, только уже для этих скрытых столбцов. Теперь другая проблема - не могу разобраться с правильным вводом Table1 в режим редактирования. Если не прописываю Table1.Edit - при открытии таблицы выдает "Table1: Dataset not in edit or insert mode", если же прописываю, то таблица открывается, но при переходе между записями вылетает "Record already locked by this session".

taras atavin, я вроде не говорил, что столбцы состоят из строк .
0
1076 / 989 / 340
Регистрация: 07.08.2012
Сообщений: 2,790
06.01.2013, 14:44
К сожалению, в BDE не силен.
И без проекта - все это догадки и домыслы.
0
Надоела реклама? Зарегистрируйтесь и она исчезнет полностью.
BasicMan
Эксперт
29316 / 5623 / 2384
Регистрация: 17.02.2009
Сообщений: 30,364
Блог
06.01.2013, 14:44
Помогаю со студенческими работами здесь

Для матрицы из 2 строк и 9 столбцов отпечатать среднее арифметическое
Для матрицы из 2 строк и 9 столбцов отпечатать среднее арифметическое элементов каждого столбца, в котором абсолютная величина этих...

Двумерный массив среднее арифметическое элементов и сумм строк,столбцов
Написать программу, которая вводит по строкам с клавиатуры двумерный массив и вычисляет сумму его элементов по столбцам, сумму его...

Найти среднее арифметическое всех наибольших элементов строк и столбцов матрицы
Дана действительная матрица размера 7х6. Найти среднее арифметическое всех наибольших элементов строк и столбцов матрицы.

Найти среднее арифметическое всех наибольших элементов строк и столбцов матрицы
Дана матрица размера 7х6. Найти среднее арифметическое всех наибольших элементов строк и столбцов матрицы. в языке Си.

Найти среднее арифметическое четных строк матрицы и количество столбцов с нулями
Сформировать вещественную матрицу размерностью 5x5. Определить: а) найти среднее арифметическое элементов из четных строка; б)...


Искать еще темы с ответами

Или воспользуйтесь поиском по форуму:
15
Ответ Создать тему
Новые блоги и статьи
Идея фильтра интернета (сервер = слой+фильтр).
Hrethgir 31.03.2026
Суть идеи заключается в том, чтобы запустить свой сервер, о чём я если честно мечтал давно и давно приобрёл книгу как это сделать. Но не было причин его запускать. Очумелые учёные напечатали на. . .
Модель здравосоХранения 6. ESG-повестка и устойчивое развитие; углублённый анализ кадрового бренда
anaschu 31.03.2026
В прикрепленном документе раздумья о том, как можно поменять модель в будущем
10 пpимет, которые всегда сбываются
Maks 31.03.2026
1. Чтобы, наконец, пришла маршрутка, надо закурить. Если сигарета последняя, маршрутка придет еще до второй затяжки даже вопреки расписанию. 2. Нaдоели зима и снег? Не надо переезжать. Достаточно. . .
Перемещение выделенных строк ТЧ из одного документа в другой
Maks 31.03.2026
Реализация из решения ниже выполнена на примере нетипового документа "ВыдачаОборудованияНаСпецтехнику" с единственной табличной частью "ОборудованиеИКомплектующие" разработанного в конфигурации КА2. . . .
Functional First Web Framework Suave
DevAlt 30.03.2026
Sauve. IO Апнулись до NET10. Из зависимостей один пакет, работает одинаково хорошо как в режиме проекта так и в интерактивном режиме. из сложностей - чисто функциональный подход. Решил. . .
Автоматическое создание документа при проведении другого документа
Maks 29.03.2026
Реализация из решения ниже выполнена на нетиповых документах, разработанных в конфигурации КА2. Есть нетиповой документ "ЗаявкаНаРемонтСпецтехники" и нетиповой документ "ПланированиеСпецтехники". В. . .
Настройка движения справочника по регистру сведений
Maks 29.03.2026
Решение ниже реализовано на примере нетипового справочника "ТарифыМобильнойСвязи" разработанного в конфигурации КА2, с целью учета корпоративной мобильной связи в коммерческом предприятии. . . .
Автозаполнение реквизита при выборе элемента справочника
Maks 27.03.2026
Программный код из решения ниже на примере нетипового документа "ЗаявкаНаРемонтСпецтехники" разработанного в конфигурации КА2. При выборе "Спецтехники" (Тип Справочник. Спецтехника), заполняется. . .
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2026, CyberForum.ru