我正在 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)
正如我在评论中所建议的那样,当您更改动态 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 件事:
HSA/ 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)
| 归档时间: |
|
| 查看次数: |
1055 次 |
| 最近记录: |