Форум программистов
 

Восстановите пароль или Зарегистрируйтесь на форуме, о проблемах и с заказом рекламы пишите сюда - alarforum@yandex.ru, проверяйте папку спам!

Вернуться   Форум программистов > Delphi программирование > БД в Delphi
Регистрация

Восстановить пароль

Купить рекламу на форуме - 42 тыс руб за месяц

Ответ
 
Опции темы Поиск в этой теме
Старый 16.08.2013, 20:03   #1
Человек_Борща
Старожил
 
Аватар для Человек_Борща
 
Регистрация: 30.12.2009
Сообщений: 11,430
Вопрос БД и календарь

Доброго времени суток!

С БД работал не очень много, потому мало чего умею.

Дали задание, создать табель сотрудников:
Отображается список сотрудников по вертикали, по горизонтали дни месяца.
В каждом дне юзер выбирает ячейку у в таблице и указывает состояние:
0 - не был
1 - был
2 - не известно

В зависимости от состояния, ячейка красится в цвет.

База данных MS SQL Server или MS Access.

Как это реализовать?

Я выбрал MS Access.

Создал базу данных, 2 таблицы:
В первой Workers поля:
Поле счетчик ID, ключ без повторов
Поле ФИО FIO

Вторая таблица Calendar:
Числовое поле ID, не ключ
Поле даты D
Поле состояния S

Связал таблицы:
От Workers.ID, к Calendar.ID, связью "Один ко многим".

Сохранил в Access 2000-2003 MDB формате.

Теперь программа:
Кинул DBGrid, ADOConnction, DataSource, ADOTable, ADOQuerty

В ADOConnection указал провайдера Jet DB 4.0 ADO Provider, и путь к файлу БД.
Запретил запрос логина и пароля и поставил Connected в True.
В ADOTable указал ADOConnection, выбрал таблицу Workers, выставил Active в True.
В DataSource выбрал ADOTable, выставил Active=True.
В DBGrid указал DataSource
В ADOQuerty указал ADOTable.

При запуске программы DBGrid отображает содержимое моей таблицы.

Но вот дилема:
1. Отображается колонка Workers.ID, я её в Run-time убираю так:
Код:
DBGrid.Columns[0].Visible:=False;
Можно ли это делать ещё в Disign-time?

2. Имена колонок "стремные", переименовываю так:
Код:
DBGrid.Columns[0].Title.Caption:='Ф.И.О.';
Можно ли это делать ещё в Disign-time?

3. На форму есть TDateTimePicker, юзер может выбирать месяц и год, который хочет посмотреть.
Пользуясь DaysInMonth функцией я узнаю сколько дней в выбранном месяце.
Мне надо перестроить таблицу, т.е. по горизонтали динамически выставить от 1 до <дней в месяце> колонки и так же пронумеровать, а затем синхронизировать с Workers.FIO и отобразить данные в соотв. с выбранным месяцем, т.е. по каждому из Workers.FIO визуально выдать кто, когда был/не был.

Как добавить это "временные колонки" в run-time?
Далее, как перебрать все Workers.ID и по ним сделать запрос в таблицу Calendar, для выборки периода между 2 датами?

Вроде бы все.

Правильно ли я понял и реализовал задачу, может есть проще вариант?
Человек_Борща вне форума Ответить с цитированием
Старый 16.08.2013, 20:12   #2
Stilet
Белик Виталий :)
Старожил
 
Аватар для Stilet
 
Регистрация: 23.07.2007
Сообщений: 57,097
По умолчанию

Цитата:
Можно ли это делать ещё в Disign-time?
Можно. В дизайне поставь ADOTable.active = true. Потом в свойствах Columns грида жимани кнопку "Добавить все поля" - в гриде в дизайне создастся структура открытой таблицы. Потом просто поубирай ненужные поля. Задай им капшн ну и марафет по вкусу.
Цитата:
по горизонтали динамически выставить от 1 до <дней в месяце>
Забей. Пусть будет полюбому 31 день. Просто из базы ты не получишь все до 31-го если такого дня нет в таблице. Не так уж и глупо, я работаю с некоторыми весьма серьезными программами, которые в модулях табелирования и нормирования так и поступают - календар на максимуме, а там показываются дни или нет не важно - пользователь полюбому знает куда тыкать, а если не знает в проге при тычке не в тот день можно условие прописать. Это дешевше чем каждый раз выясять сколько дней (да еще и при високосном)
I'm learning to live...
Stilet вне форума Ответить с цитированием
Старый 16.08.2013, 20:31   #3
Человек_Борща
Старожил
 
Аватар для Человек_Борща
 
Регистрация: 30.12.2009
Сообщений: 11,430
По умолчанию

Цитата:
Можно. В дизайне поставь ADOTable.active = true. Потом в свойствах Columns грида жимани кнопку "Добавить все поля" - в гриде в дизайне создастся структура открытой таблицы. Потом просто поубирай ненужные поля. Задай им капшн ну и марафет по вкусу.
Благодарю, помогло. Только не DBGrid.Columns а ADOTable.Fields

Цитата:
Забей. Пусть будет полюбому 31 день. Просто из базы ты не получишь все до 31-го если такого дня нет в таблице. Не так уж и глупо, я работаю с некоторыми весьма серьезными программами, которые в модулях табелирования и нормирования так и поступают - календар на максимуме, а там показываются дни или нет не важно - пользователь полюбому знает куда тыкать, а если не знает в проге при тычке не в тот день можно условие прописать. Это дешевше чем каждый раз выясять сколько дней (да еще и при високосном)
Нет, нет. Вы не совсем поняли.

Кинул я ещё 1 ADOTable, указал ему таблицу Calendar.

Теперь основываясь на связи Workers.ID с Calendar.ID, мне надо для каждой записи Workers.ID сделать выборку указанного промежутка времени(01.08.2013-31.08.2013) и все найденные даты визуализировать в DBGrid.

Собственно как это сделать? В таблице должно отображаться кол-во дней в месяце по горизонтали 100%, но как?

Вертикаль берется из таблицы Workers а горизонталь из таблицы Calendar, как из связать и обработать?
Человек_Борща вне форума Ответить с цитированием
Старый 16.08.2013, 20:59   #4
Аватар
Старожил
 
Аватар для Аватар
 
Регистрация: 17.11.2010
Сообщений: 18,922
По умолчанию

При такой структуре для отображения табеля в гриде ADOTable не помощник. Нужно запросом выбирать, транспонируя данные из таблицы Calendar. Кстати в ACCESSE по-моему есть конструктор для перекрестных запросов, но никогда не пользовался им
Если бы архитекторы строили здания так, как программисты пишут программы, то первый залетевший дятел разрушил бы цивилизацию
Аватар вне форума Ответить с цитированием
Старый 16.08.2013, 21:16   #5
Человек_Борща
Старожил
 
Аватар для Человек_Борща
 
Регистрация: 30.12.2009
Сообщений: 11,430
По умолчанию

Цитата:
При такой структуре для отображения табеля в гриде ADOTable не помощник. Нужно запросом выбирать, транспонируя данные из таблицы Calendar.
Придумал такое:
Заменяю DBGrid на обычный Grid.
Как мне руками перебирать данные таблиц и вставлять в мой Grid?
Человек_Борща вне форума Ответить с цитированием
Старый 16.08.2013, 21:39   #6
ReportCube
Форумчанин
 
Аватар для ReportCube
 
Регистрация: 11.03.2011
Сообщений: 426
По умолчанию

Почитайте про кросс-таблицы, там всё достаточно просто, одна таблица связи на большинство случаев жизни - и запросы простые, и скорость высокая
ReportCube вне форума Ответить с цитированием
Старый 16.08.2013, 22:31   #7
Аватар
Старожил
 
Аватар для Аватар
 
Регистрация: 17.11.2010
Сообщений: 18,922
По умолчанию

Цитата:
Почитайте про кросс-таблицы
Да, стоит посмотреть создание таких запросов в ACCESS. Без него запрос для грида мог бы выглядеть примерно так
Код:
SELECT W.ID,W.FIO,
    MAX(IIF(DAY(C.D)=1,C.S,0)) AS d1,
    MAX(IIF(DAY(C.D)=2,C.S,0)) AS d2,
...
    MAX(IIF(DAY(C.D)=31,C.S,0)) AS d31
  FROM Workers W,Calendar C
  WHERE W.ID=C.ID AND YEAR(C.D)=2013 AND MONTH(C.D)=7
  GROUP BY W.ID,W.FIO
При условии, что в Calendar ID,D - составной ключ и в дате нет времени
Если бы архитекторы строили здания так, как программисты пишут программы, то первый залетевший дятел разрушил бы цивилизацию
Аватар вне форума Ответить с цитированием
Старый 17.08.2013, 00:43   #8
Человек_Борща
Старожил
 
Аватар для Человек_Борща
 
Регистрация: 30.12.2009
Сообщений: 11,430
По умолчанию

Цитата:
Забей. Пусть будет полюбому 31 день. Просто из базы ты не получишь все до 31-го если такого дня нет в таблице. Не так уж и глупо, я работаю с некоторыми весьма серьезными программами, которые в модулях табелирования и нормирования так и поступают - календар на максимуме, а там показываются дни или нет не важно - пользователь полюбому знает куда тыкать, а если не знает в проге при тычке не в тот день можно условие прописать. Это дешевше чем каждый раз выясять сколько дней (да еще и при високосном)
Вернулся к вашему варианту.

Но как добавить свои колонки если реальных данных в DB нет?
При запуске ПО из БД берутся ФИО и записываются в колонку ФИО, и все вроде бы шоколадно, но если я пытаюсь добавить свои колонки:
Код:
var
  i, iDays: Integer;
  Col: TColumn;
begin
  iDays := DaysInMonth(DateCombo.Date);
  for i := 1 to iDays do
  begin
    Col := Grid.Columns.Add;
    with Col do
    begin
      Col.Title.Alignment := taCenter;
      Col.Title.Caption := IntToStr(i);
    end;
  end;
То колонка ФИО(та что из БД и реально там есть), тупо пропадает.

Как лечить?

Почитал про перекрестные запросы - пока рано для меня.
Человек_Борща вне форума Ответить с цитированием
Старый 17.08.2013, 00:49   #9
northener
ПШП
Участник клуба
 
Регистрация: 15.07.2013
Сообщений: 1,896
По умолчанию

Цитата:
но если я пытаюсь добавить свои колонки:
Если вы сами в дизайнтайм или в рантайме создадите одну или несколько колонок, то именно они и только они и будут показаны в гриде. То же самое относится и к компонентам "поля датасета". Если вами заданы и те и другие показаны будут те, которые вы задали и для колонок и для полей. Если вы ничего сами не задали показано будет всё что возможно.
northener вне форума Ответить с цитированием
Старый 17.08.2013, 02:00   #10
Человек_Борща
Старожил
 
Аватар для Человек_Борща
 
Регистрация: 30.12.2009
Сообщений: 11,430
По умолчанию

northener, плюсую. Помогли. Я добавил Field к DBGrid.Columns и добавление в Run-time заработало совместно с тек. полями в БД.

Теперь вопрос другой, надо отобразить данные БД в таблице, визуально.
Как перебрать все Workers и получить их ID и для каждого сделать выборку по выбранному месяцу и году, и получить дни?

Вот я в MS access наклепал запрос:
Код:
SELECT Calendar.Day, Calendar.State
FROM Workers INNER JOIN Calendar ON Workers.[ID] = Calendar.[ID]
WHERE (Calendar.ID=1) AND
( DatePart("m",Calendar.Day) = DatePart("m",#8/10/2013#) AND DatePart("yyyy",Calendar.Day) = DatePart("yyyy",#8/10/2013#));
Запрос выбирает все даты с Calendar.ID = <Текущий Workers.ID в моём цикле>, и где
месяц и год совпадают с указанной датой в DateTimePicker.

Как перебрать всех пользователей? Может цикл какой есть?

Пробую так:
Код:
procedure TMainForm.BuildGrid;
var
  i, iDays: Integer;
  Col: TColumn;
  sID: string;
begin
  iDays := DaysInMonth(DateCombo.Date);
  Grid.Columns.Clear;
  Grid.Columns.RebuildColumns;
  Grid.Columns[0].Visible := False;
  for i := 1 to iDays do
  begin
    Col := Grid.Columns.Add;
    with Col do
    begin
      Col.Title.Alignment := taCenter;
      Col.Title.Caption := IntToStr(i);
    end;
  end;

  if not CalendarTbl.IsEmpty then
  begin
    WorkersTbl.First;
    repeat
      sID := WorkersTbl.Fields[0].AsString;
      DBQuerty.SQL.Clear;
      DBQuerty.SQL.Add('SELECT Calendar.Day, Calendar.State');
      DBQuerty.SQL.Add('FROM Workers INNER JOIN Calendar ON Workers.[ID] = Calendar.[ID]');
      DBQuerty.SQL.Add('WHERE (Calendar.ID=' + sID + ') AND');
      DBQuerty.SQL.Add('( DatePart("m",Calendar.Day) = DatePart("m",#' + FormatDateTime('dd/mm/yyyy', fDate) + '#)');
      DBQuerty.SQL.Add('AND DatePart("yyyy",Calendar.Day) = DatePart("yyyy",#' + FormatDateTime('dd/mm/yyyy', fDate) + '#))');
      DBQuerty.ExecSQL;

      DBQuerty.First; //Пишет, что Dataset закрыт. 
      repeat
        iDays := DayOfTheMonth(DBQuerty.Fields[0].Value);

        DBQuerty.Next;
      until DBQuerty.Eof;

      WorkersTbl.Next;
    until WorkersTbl.Eof;
  end;
end;
Заранее спрошу, результат ADOQuerty никуда сам не вылезает, я сам должен его обработать?
Если да, то это очень хорошо, и как мне обращаться с результатом запроса?
Если нет, то как быть?

Последний раз редактировалось Человек_Борща; 17.08.2013 в 02:27.
Человек_Борща вне форума Ответить с цитированием
Ответ


Купить рекламу на форуме - 42 тыс руб за месяц



Похожие темы
Тема Автор Раздел Ответов Последнее сообщение
Календарь sid1868 Общие вопросы Delphi 1 04.05.2011 19:55
Календарь sid1868 Помощь студентам 1 04.05.2011 19:16
БД и календарь torrtik БД в Delphi 2 10.04.2011 19:14
Календарь krikaved Общие вопросы Delphi 2 25.03.2010 22:58
Календарь ruavia3 Microsoft Office Excel 6 16.04.2009 15:32