如何更改从 mysql 生成的报告的特定日期的值

Nar*_*_CH 1 mysql

我正在 mysql 中生成出勤报告,通过从 3 个表中提取数据,例如从招生表中提取学生姓名和卷号,缺席表中的缺席详细信息,并且我创建了一个日历表来生成所需的输出我可以在这里生成输出我的数据库和我生成的结果。SQL小提琴

现在我想将表中出现“SUN”的任何位置显示为“S”,并且如果报告中有任何假期日期,则应将它们显示为“H”。

谁能告诉我在查询中我应该怎么做才能产生预期的结果?

我的数据:

CREATE TABLE tbl_admission
    (`StudentName` varchar(5), `RollNo` int, `Class` int)
;

INSERT INTO tbl_admission
    (`StudentName`, `RollNo`, `Class`)
VALUES
    ('Naren', 1, 22),
    ('Srinu', 2, 22),
    ('Blah', 3, 22)
;

CREATE TABLE tbl_absentees
    (`Date` datetime, `Status` varchar(1), `RollNo` int, `Class` int)
;

INSERT INTO tbl_absentees
    (`Date`, `Status`, `RollNo`, `Class`)
VALUES
    ('2013-06-01 00:00:00', 'A', 1, 22),
    ('2013-06-02 00:00:00', 'A', 1, 22),
    ('2013-06-03 00:00:00', 'A', 1, 22),
    ('2013-06-04 00:00:00', 'A', 1, 22),
    ('2013-06-05 00:00:00', 'A', 1, 22),
    ('2013-06-06 00:00:00', 'A', 1, 22),
    ('2013-06-07 00:00:00', 'A', 1, 22),
    ('2013-06-08 00:00:00', 'A', 1, 22),
    ('2013-06-09 00:00:00', 'A', 1, 22),
    ('2013-06-10 00:00:00', 'A', 1, 22),
    ('2013-06-11 00:00:00', 'A', 1, 22),
    ('2013-06-12 00:00:00', 'A', 1, 22),
    ('2013-06-13 00:00:00', 'A', 1, 22),
    ('2013-06-14 00:00:00', 'A', 1, 22),
    ('2013-06-15 00:00:00', 'A', 1, 22),
    ('2013-06-16 00:00:00', 'A', 1, 22),
    ('2013-06-17 00:00:00', 'A', 1, 22),
    ('2013-06-18 00:00:00', 'A', 1, 22),
    ('2013-06-19 00:00:00', 'A', 1, 22),
    ('2013-06-20 00:00:00', 'A', 1, 22)
;

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'),
    ('2013-06-11 00:00:00'),
    ('2013-06-12 00:00:00'),
    ('2013-06-13 00:00:00'),
    ('2013-06-14 00:00:00'),
    ('2013-06-15 00:00:00'),
    ('2013-06-16 00:00:00'),
    ('2013-06-17 00:00:00'),
    ('2013-06-18 00:00:00'),
    ('2013-06-19 00:00:00'),
    ('2013-06-20 00:00:00');

CREATE TABLE `tbl_holidays` (
  `id` int(11) NOT NULL auto_increment,
  `Hname` varchar(60) NOT NULL,
  `Htype` varchar(45) default NULL,
  `StartDate` date default NULL,
  `ToDate` date default NULL,
  `Descr` varchar(75) default NULL,
  `status` tinyint(4) default '1',
  PRIMARY KEY  (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1;

INSERT INTO `tbl_holidays` (`id`, `Hname`, `Htype`, `StartDate`, `ToDate`, `Descr`, `status`) VALUES (1,'Independence Day','Mandatory','2013-08-15','2013-08-15','It is Mandatory Holiday',1),(2,'Ramzan','Optional','2013-09-09','2013-09-09','It is Optional Holiday',1),(3,'UGADHI','Mandatory','2013-07-01','2013-07-02','efdrvb ',1);
Run Code Online (Sandbox Code Playgroud)

我当前的代码:

set session group_concat_max_len= 2048;

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, '%a %d'), '`'
    )
  ) INTO @sql
FROM calendar
where date>='2013-06-01'
  and date <= '2013-06-12';

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;
Run Code Online (Sandbox Code Playgroud)

Tar*_*ryn 6

正如我在评论中所建议的那样,当您更改动态 SQL 解决方案的代码时,我总是建议您首先编写 SQL 查询,以便您可以获得正确的 JOIN 和逻辑,然后将其转换为动态 SQL。

要获得结果,您需要做的第一件事是将tbl_Holidays. 我会通过将它加入您的calendar表来开始查询,然后您可以轻松确定哪些日期是假期:

select c.date, 
  case when h.startdate is null then 'N' else 'Y' end holiday
from calendar c
left join tbl_holidays h
  on c.date = h.startdate;
Run Code Online (Sandbox Code Playgroud)

获得日期和假期列表后,就像您之前的查询一样,您将将此结果交叉连接到tbl_admission

select ch.date, ch.holiday, a.studentname, a.rollno, a.class
from
(
  select c.date, 
    case when h.startdate is null then 'N' else 'Y' end holiday
  from calendar c
  left join tbl_holidays h
    on c.date = h.startdate
) ch
cross join tbl_admission a;
Run Code Online (Sandbox Code Playgroud)

演示。这将为您提供所有日期、假期和学生的列表,然后您可以加入这些学生tbl_absentees以确定每天谁在场/缺席。

现在,由于您希望根据当天是星期日还是假日来更改结果中的显示值,因此您需要更改原始 CASE 表达式。新代码将类似于以下内容:

max(CASE WHEN ca.date = '2013-06-01' then
      case 
          when ca.holiday = 'Y'  then 'H'
          when dayname(ca.date) = 'SUNDAY' then 'S' 
          else coalesce(p.status, 'P') end END) AS `SAT 01`
Run Code Online (Sandbox Code Playgroud)

新的 CASE 表达式做了 4 件事:

  1. 检查日期
  2. 如果日期是假日,则显示一个 H
  3. 如果日期是星期日,则显示 S
  4. 如果不是假期或星期日,则显示您最初拥有的A/ P

将整个代码放在一起,您将拥有一个静态版本的查询,如下所示:

SELECT ca.studentname,
  ca.rollno,
  ca.class,
  max(CASE WHEN ca.date = '2013-06-01' then
          case 
              when ca.holiday = 'Y'  then 'H' 
              when dayname(ca.date) = 'SUNDAY' then 'S' 
              else coalesce(p.status, 'P') end END) AS `SAT 01`,
  max(CASE when ca.date = '2013-06-02' then
        case
          when ca.holiday = 'Y'  then 'H'
          when dayname(ca.date) = 'SUNDAY' then 'S' 
          else coalesce(p.status, 'P') end END) AS `SUN 02`,
  max(CASE WHEN ca.date = '2013-06-03' then
        case 
          when ca.holiday = 'Y'  then 'H' 
          when dayname(ca.date) = 'SUNDAY' then 'S' 
          else coalesce(p.status, 'P') end END) AS `MON 03`
from
(
  select ch.date, ch.holiday, a.studentname, a.rollno, a.class
  from
  (
    select c.date, 
      case when h.startdate is null then 'N' else 'Y' end holiday
    from calendar c
    left join tbl_holidays h
      on c.date = h.startdate
  ) ch
  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;
Run Code Online (Sandbox Code Playgroud)

请参阅SQL Fiddle with Demo。现在您有了一个带有工作逻辑的静态版本,您可以将其转换为动态 SQL 代码:

set session group_concat_max_len= 5000;

SET @sql = NULL;
SELECT
  GROUP_CONCAT(DISTINCT
    CONCAT(
      'max(CASE WHEN ca.date = ''',
      date_format(date, '%Y-%m-%d'),
      ''' THEN 
            case 
              when ca.holiday = ''Y'' then ''H'' 
              when dayname(ca.date)=''Sunday'' then ''S''
              else coalesce(p.status, ''P'') end end) AS `',
      date_format(date, '%a %d'), '`'
    )
  ) INTO @sql
FROM calendar
where date>='2013-06-01'
  and date <= '2013-06-12';

SET @sql 
  = CONCAT('SELECT ca.studentname,
              ca.rollno,
              ca.class, ', @sql, ' 
            from
            (
              select ch.date, ch.holiday, a.studentname, a.rollno, a.class
              from
              (
                select c.date, 
                  case when h.startdate is null then ''N'' else ''Y'' end holiday
                from calendar c
                left join tbl_holidays h
                  on c.date = h.startdate
              ) ch
              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;
Run Code Online (Sandbox Code Playgroud)

请参阅SQL Fiddle with Demo。一些旁注,由于您在 sql 字符串中添加了明显更多的字符,因此您可能需要增加group_concat_max_len. 此外,您可以通过使用 MySQL 的缩写IF()逻辑来替换CASE表达式来减少字符数。

这个新版本的代码会给你一个结果:

| STUDENTNAME | ROLLNO | CLASS | SAT 01 | SUN 02 | MON 03 | TUE 04 | WED 05 | THU 06 | FRI 07 | SAT 08 | SUN 09 | MON 10 | TUE 11 | WED 12 |
--------------------------------------------------------------------------------------------------------------------------------------------
|       Naren |      1 |    22 |      A |      S |      H |      A |      A | (null) | (null) | (null) | (null) | (null) | (null) | (null) |
|       Srinu |      2 |    22 |      P |      S |      H |      P |      P | (null) | (null) | (null) | (null) | (null) | (null) | (null) |
|        Blah |      3 |    22 |      P |      S |      H |      P |      P | (null) | (null) | (null) | (null) | (null) | (null) | (null) |
Run Code Online (Sandbox Code Playgroud)

  • @Narendar_CH 请不要强迫用户查看其他问题。如果你写了一个有趣的问题,人们会找到它。 (2认同)