Показать ежемесячный отчет о посещаемости в MySql

8

Я делаю систему управления школой в php, используя Mysql DB. Я застрял в моем проекте. Пожалуйста, кто-нибудь подскажет, что я делаю неправильно.

У меня есть две таблицы в моей базе данных; один для хранения Studentsзаписей другой для хранения своих attendanceдней

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

Я написал запрос SQL для отображения результата здесь:

SELECT tab.class, attend, DATE, ta.rollno, ta.StdNm 
FROM tbl_absentees tab, tbl_admission ta
WHERE ta.Cls = class
  AND ta.rollno = tab.rollno
  AND class =22
  AND attend =  'A'
  AND DATE =  '2013-06-07';

Результат:

Class Attend RollNo StudentName

Но я хочу отображать в виде таблицы 31 день, принимая только дату в таблице посещаемости, если посещаемость = A отображает A для отсутствующих дней, в противном случае отображает «P» для оставшихся дней

Как я могу сделать это в MySQL? Может кто-нибудь предложить / дать мне идею для достижения этой цели.

Извините за неправильное разъяснение в моем вопросе. На самом деле я хочу отобразить отчет о посещаемости за определенный месяц, где данные поступают из двух таблиц:

  • первая таблица состоит из StudentName, RollNo, Class
  • вторая таблица состоит из даты, статуса, RollNo, класса

Теперь я хочу отобразить отчет, как это .

Narendar_CH
источник

Ответы:

18

Этот тип вращения данных от столбцов к строкам известен как PIVOT. MySQL не имеет сводной функции, но вы можете использовать агрегатную функцию с выражением CASE для получения результата.

Моим первым предложением было бы определить, есть ли у вас calendarтаблица или таблица, содержащая все даты, которые вы хотите отобразить. Если нет, то я бы предложил создать такой, подобный следующему:

CREATE TABLE calendar (`Date` datetime) ;

INSERT INTO calendar (`Date`)
VALUES
    ('2013-06-01 00:00:00'),
    ('2013-06-02 00:00:00'),
    ('2013-06-03 00:00:00'),
    ('2013-06-04 00:00:00'),
    ('2013-06-05 00:00:00'),
    ('2013-06-06 00:00:00'),
    ('2013-06-07 00:00:00'),
    ('2013-06-08 00:00:00'),
    ('2013-06-09 00:00:00'),
    ('2013-06-10 00:00:00');

Это позволит вам создать список всех дат, которые вы хотите отобразить.

Во-вторых, вам нужно будет составить список каждого студента и каждой даты. Вы можете сделать это, используя CROSS JOIN между вами tbl_admissionи calendarстолом:

select c.date, a.studentname, a.rollno, a.class
from calendar c
cross join tbl_admission a;

Смотрите Демо . Если у вас есть этот список, вы можете использовать левое соединение с существующей tbl_absenteesтаблицей, чтобы получить результат:

select 
  ca.studentname,
  ca.rollno,
  ca.class,
  max(case when ca.date = '2013-06-01' then coalesce(p.status, 'P') end) `2013-06-01`,
  max(case when ca.date = '2013-06-02' then coalesce(p.status, 'P') end) `2013-06-02`,
  max(case when ca.date = '2013-06-03' then coalesce(p.status, 'P') end) `2013-06-03`,
  max(case when ca.date = '2013-06-04' then coalesce(p.status, 'P') end) `2013-06-04`,
  max(case when ca.date = '2013-06-05' then coalesce(p.status, 'P') end) `2013-06-05`,
  max(case when ca.date = '2013-06-06' then coalesce(p.status, 'P') end) `2013-06-06`,
  max(case when ca.date = '2013-06-07' then coalesce(p.status, 'P') end) `2013-06-07`,
  max(case when ca.date = '2013-06-08' then coalesce(p.status, 'P') end) `2013-06-08`,
  max(case when ca.date = '2013-06-08' then coalesce(p.status, 'P') end) `2013-06-09`,
  max(case when ca.date = '2013-06-10' then coalesce(p.status, 'P') end) `2013-06-10`
from
(
  select c.date, a.studentname, a.rollno, a.class
  from calendar c
  cross join tbl_admission a
) ca
left join tbl_absentees p
  on ca.rollno = p.rollno
  and ca.date = p.date
group by ca.studentname, ca.rollno, ca.class
order by ca.rollno;

Смотрите SQL Fiddle с демонстрацией . Конечно, для вашего запроса вы, скорее всего, захотите запросить данные на основе диапазона дат, поэтому вам не нужно будет жестко кодировать значения. Если это так, то вам нужно взглянуть на использование подготовленного оператора для генерации динамического SQL:

SET @sql = NULL;
SELECT
  GROUP_CONCAT(DISTINCT
    CONCAT(
      'max(CASE WHEN ca.date = ''',
      date_format(date, '%Y-%m-%d'),
      ''' THEN coalesce(p.status, ''P'') END) AS `',
      date_format(date, '%Y-%m-%d'), '`'
    )
  ) INTO @sql
FROM calendar
where date>='2013-06-01'
  and date <= '2013-06-05';

SET @sql 
  = CONCAT('SELECT ca.studentname,
              ca.rollno,
              ca.class, ', @sql, ' 
            from
            (
              select c.date, a.studentname, a.rollno, a.class
              from calendar c
              cross join tbl_admission a
            ) ca
            left join tbl_absentees p
              on ca.rollno = p.rollno
              and ca.date = p.date
            where ca.date>=''2013-06-01''
              and ca.date <= ''2013-06-05''
            group by ca.studentname, ca.rollno, ca.class
            order by ca.rollno');

PREPARE stmt FROM @sql;
EXECUTE stmt;
DEALLOCATE PREPARE stmt;

Смотрите SQL Fiddle с демонстрацией . Оба эти запроса будут давать результат, аналогичный следующему:

| STUDENTNAME | ROLLNO | CLASS | 2013-06-01 | 2013-06-02 | 2013-06-03 | 2013-06-04 | 2013-06-05 | 2013-06-06 | 2013-06-07 | 2013-06-08 | 2013-06-09 | 2013-06-10 |
------------------------------------------------------------------------------------------------------------------------------------------------------------------
|       Naren |      1 |    22 |          A |          A |          A |          A |          P |          P |          P |          P |          P |          P |
|       Srinu |      2 |    22 |          P |          P |          P |          P |          P |          P |          P |          P |          P |          P |
|        Blah |      3 |    22 |          A |          P |          P |          P |          P |          P |          P |          P |          P |          P |
Тарын
источник