【问题标题】:SQL Server : case multiple column statuesSQL Server:案例多列状态
【发布时间】:2017-05-07 02:58:29
【问题描述】:

我一直在尝试获取学生参加的总时间。我想通过使用没有运气的案例语句来获得它。在我的桌子上,每个小时可以有 3 个雕像之一(出席、缺席、缺席有借口),也可以有 null

Attendance_Daily Table 格式 Hour_X 可以是 1 或 2 或 3 表示(出席、缺席、缺席有借口)

StudentID| GroupID| date | Hour_1 | Hour_2 | Hour_3 | Hour_4 | Hour_5 | Hour_6 | Hour_7 | Hour_8

组(类)表格格式

Group_ID | Group_Name | Course_ID | Attendance_Type | Attempts_for_attendance | Instructor_ID | Start_Date | End_Date | Start_Time| End_Time 

类数据示例

Group_ID | Group_Name | Course_ID | Attendance_Type | Attempts_for_taking_attendance_perday |Instructor_ID | Start_Date | End_Date | Start_Time| End_Time |
---------+------------+-----------+-----------------+---------------------------------------+--------------+------------+----------+-----------+----------+-----
    1    |sql class 1 | 1         |       1         |                   1                   |    1         | 01-01-2017 |30-01-2017 |8:00 AM   | 12:00 PM
    1    |sql class 2 | 1         |       2         |                   3                   |    2         | 01-01-2017 |30-01-2017 |8:00 AM   | 12:00 PM

需要最终结果总列 示例和案例:结果可以是:

参加的小时数

或在雕像 2 小时时将 A 作为字符串代码

或在雕像 3 小时时将 E 作为字符串代码

StudentID | Date       | Total Result | Note only not in result
----------+------------+--------------+--------------------------------------
    1     | 30-05-2017 | 8            |hours attended statues 1
    2     | 30-05-2017 | 3            |hours attended statues 1
    3     | 30-05-2017 | A            |absent none of the hours attended
    4     | 30-05-2017 | E            |absent with excuse>>  none of the hours attended >> statues 3
    5     | 30-05-2017 | 3             |need attended total 3  , when  3 hours attended  and absent 3 hours 

希望能帮到你

【问题讨论】:

标签: sql sql-server switch-statement case


【解决方案1】:

请尝试以下...

SELECT StudentID,
       [date],
       CASE
           WHEN Group_Type = 'daily' AND
                CountPresent = 0 AND
                CountAbsent = 0 AND
                CountExcused = 0 THEN
               'A : Absent for the day'
           WHEN Group_Type = 'hourly' AND
                Group_Frequency = 1 AND
                CountPresent = 0 AND
                CountAbsent = 0 AND
                CountExcused = 0 THEN
               'A : Absent with the hour not attended'
           WHEN Group_Type = 'hourly' AND
                Group_Frequency > 1 AND
                CountPresent = 0 AND
                CountAbsent = 0 AND
                CountExcused = 0 THEN
               'A : Absent with none of the hours attended'
           WHEN Group_Type = 'daily' AND
                CountPresent = 0 AND
                CountAbsent = 1 AND
                CountExcused = 0 THEN
               'A : Absent for the day, with 1 statue'
           WHEN Group_Type = 'hourly' AND
                Group_Frequency = 1 AND
                CountPresent = 0 AND
                CountAbsent = 1 AND
                CountExcused = 0 THEN
               'A : Absent with the hour not attended, with 1 statue'
           WHEN Group_Type = 'hourly' AND
                Group_Frequency > 1 AND
                CountPresent = 0 AND
                CountAbsent = Group_Frequency AND
                CountExcused = 0 THEN
               'A : Absent with none of the hours attended, with ' +
                   CountAbsent +
                   IIF( CountAbsent = 1, ' statue', ' statues' )
           WHEN Group_Type = 'daily' AND
                CountPresent = 0 AND
                CountAbsent = 0 AND
                CountExcused = 1 THEN
               'E : Excused for the day, with 1 statue' )
           WHEN Group_Type = 'hourly' AND
                Group_Frequency = 1 AND
                CountPresent = 0 AND
                CountAbsent = 0 AND
                CountExcused = 1 THEN
               'E : Excused for the hour, with 1 statue'
           WHEN Group_Type = 'hourly' AND
                Group_Frequency > 1 AND
                CountPresent = 0 AND
                CountAbsent = 0 AND
                CountExcused = Group_Frequency THEN
               'E : Excused for the ' +
                   CountExcused +
                   ' hours, with ` +
                   CountExcused +
                   ' statues'
           WHEN Group_Type = 'daily' AND
                CountPresent = 1 AND
                CountAbsent = 0 AND
                CountExcused = 0 THEN
               'Present for the day, with 1 statue'                   
           WHEN Group_Type = 'hourly' AND
                Group_Frequency = 1 AND
                CountPresent = 1 AND
                CountAbsent = 0 AND
                CountExcused = 0 THEN
               'Present for the hour, with 1 statue'                   
           WHEN Group_Type = 'hourly' AND
                Group_Frequency > 1 AND
                CountPresent = Group_Frequency AND
                CountAbsent = 0 AND
                CountExcused = 0 THEN
               'Present for the ' +
                   CountPresent +
                   ' hours, with ' +
                   CountPresent +
                   ' statues'
           WHEN Group_Type = 'hourly' AND
                ( CountPresent + CountAbsent ) <= Group_Frequency
                CountPresent > 0 AND
                CountAbsent > 0 AND
                CountExcused = 0 THEN
               'Present for ' +
                   CountPresent +
                   IIF( CountPresent = 1, ' hour', ' hours' ) +
                   ', Absent for ' +
                   IIF( CountAbsent = 1, ' hour', ' hours' ) +
                   ', with ' +
                   ( CountPresent + CountAbsent ) +
                   ' statues'
           WHEN Group_Type = 'hourly' AND
                ( CountPresent + CountExcused ) <= Group_Frequency
                CountPresent > 0 AND
                CountAbsent = 0 AND
                CountExcused > 0 THEN
               'Present for ' +
                   CountPresent +
                   IIF( CountPresent = 1, ' hour', ' hours' ) +
                   ', Excused for ' +
                   IIF( CountExcused = 1, ' hour', ' hours' ) +
                   ', with ' +
                   ( CountPresent + CountExcused ) +
                   ' statues'
           WHEN Group_Type = 'hourly' AND
                ( CountAbsent + CountExcused ) <= Group_Frequency
                CountPresent = 0 AND
                CountAbsent > 0 AND
                CountExcused > 0 THEN
               'Absent for ' +
                   CountAbsent +
                   IIF( CountAbsent = 1, ' hour', ' hours' ) +
                   ', Excused for ' +
                   IIF( CountExcused = 1, ' hour', ' hours' ) +
                   ', with ' +
                   ( CountAbsent + CountExcused ) +
                   ' statues'
           WHEN Group_Type = 'hourly' AND
                ( CountPresent + CountAbsent + CountExcused ) <= Group_Frequency
                CountPresent > 0 AND
                CountAbsent > 0 AND
                CountExcused > 0 THEN
               'Present for ' +
                   CountPresent +
                   IIF( CountPresent = 1, ' hour', ' hours' ) +
                   'Absent for ' +
                   CountAbsent +
                   IIF( CountAbsent = 1, ' hour', ' hours' ) +
                   ', Excused for ' +
                   IIF( CountExcused = 1, ' hour', ' hours' ) +
                   ', with ' +
                   ( CountPresent + CountAbsent + CountExcused ) +
                   ' statues'
           ELSE
               'Unexpected combination (GT = ' +
               Group_Type +
               ', GF = ' +
               Group_Frequency +
               ', CP = ' +
               CountPresent +
               ', CA = ' +
               CountAbsent +
               ', CE = ' +
               CountExcused
           END AS [Total Result]
FROM ( SELECT StudentID AS StudentID,
              [date] AS [date],
              IIF( Hour_1 = 1, 1, 0 ) +
                  IIF( Hour_2 = 1, 1, 0 ) +
                  IIF( Hour_3 = 1, 1, 0 ) +
                  IIF( Hour_4 = 1, 1, 0 ) +
                  IIF( Hour_5 = 1, 1, 0 ) +
                  IIF( Hour_6 = 1, 1, 0 ) +
                  IIF( Hour_7 = 1, 1, 0 ) +
                  IIF( Hour_8 = 1, 1, 0 ) AS CountPresent,
              IIF( Hour_1 = 2, 1, 0 ) +
                  IIF( Hour_2 = 2, 1, 0 ) +
                  IIF( Hour_3 = 2, 1, 0 ) +
                  IIF( Hour_4 = 2, 1, 0 ) +
                  IIF( Hour_5 = 2, 1, 0 ) +
                  IIF( Hour_6 = 2, 1, 0 ) +
                  IIF( Hour_7 = 2, 1, 0 ) +
                  IIF( Hour_8 = 2, 1, 0 ) AS CountAbsent,
              IIF( Hour_1 = 3, 1, 0 ) +
                  IIF( Hour_2 = 3, 1, 0 ) +
                  IIF( Hour_3 = 3, 1, 0 ) +
                  IIF( Hour_4 = 3, 1, 0 ) +
                  IIF( Hour_5 = 3, 1, 0 ) +
                  IIF( Hour_6 = 3, 1, 0 ) +
                  IIF( Hour_7 = 3, 1, 0 ) +
                  IIF( Hour_8 = 3, 1, 0 ) AS CountExcused,
       FROM tblAttendances
    ) AS countsFinder
JOIN ( SELECT StudentID,
              Group_Type,
              Group_Frequency
       FROM tblAttendences
       JOIN tblClass ON tblAttendances.GroupID = tblClass.GroupID
       GROUP BY StudentID,
                Group_Type,
                Group_Frequency
     ) AS StudentGroupDetails ON countsFinder.StudentID = StudentGroupDetails.StudentID
ORDER BY StudentID,
         [date];

此语句首先使用 IIF() 函数比较从 tblAttendances1 的每条记录的 Hour_n 的每个值(表示 Present 的值)并返回 1 的值相等的地方并在他们没有的地方返回0。测试完 Hour_n 的所有值后,将返回的值相加,计算出有多少 Hour_n 的值等于 1

对于Hour_n 的每个值等于2(对于Absent)和Hour_n 的每个值等于3 重复相同的过程。结果计数以及该记录的[date]StudentID 的值将添加到要由子查询返回的数据集中。

在子查询对每条记录执行此过程后,生成的数据集将连接到子查询返回的数据集,该子查询列出每个 StudentID 及其对应的 Group_TypeGroup_Frequency 值。

这为我们提供了一个连接数据集,其中包含StudentID 的每个值及其对应的Group_TypeGroup_Frequency 值以及[date]CountPresentCountAbsentCountExcused 的每个对应值.

然后,每条记录的值用于SELECTStudentID[date] 值以及基于其他值组合的消息。

如果您有任何问题或cmets,请随时发表评论。

【讨论】:

  • 这位天才谢谢你,但在某些情况下结果不正确,我的总参加时间增加了一个,你可以检查一下
  • 这是完美的,引导我找到我正在寻找的答案并解决了主要问题,另一个答案也很好,非常感谢大家
【解决方案2】:

所以您的餐桌出勤率存储了哪个学生的信息 (由 student_id 标识)在哪个班级(由 group_id 标识) 在哪一天(由日期确定) 在哪一课(由日期确定) HOUR_X)?

出勤表

首先,让我们看看您的表架构(没有类列,只有 3 个句点):

CREATE TABLE IF NOT EXISTS attendance_daily (
student_id int, day date, period1 text, period2 text, period3 text);

还有一些样本数据:

INSERT INTO attendance_daily 
VALUES (1, '2017-01-01', 'present', 'present', 'present'),
       (2, '2017-01-01', 'present', 'absent', 'excused');

对于两个学生,一个三个小时都在场,另一个在第一个小时出现,第二个小时缺席,第三个小时被医生原谅。

下面是我们如何将这 2 行变成 6 行,但具有共同的属性(id、day、period):

SELECT t.id, t.day, t.period FROM  
  (SELECT student_id, day, period1 FROM attendance_daily  
   UNION ALL SELECT student_id, day, period2 FROM attendance_daily  
   UNION ALL SELECT student_id, day, period3 FROM attendance_daily  
  ) AS t (id, day, period)  
ORDER BY id, day, period;  

返回

 id |    day     | period  
----+------------+---------
  1 | 2017-01-01 | present
  1 | 2017-01-01 | present
  1 | 2017-01-01 | present
  2 | 2017-01-01 | absent
  2 | 2017-01-01 | excused
  2 | 2017-01-01 | present

UNION ALL 是必需的,否则id = 1 将只有 1 行,而不是 3!

并计算存在状态(statuses):

SELECT t.id, t.day, t.presence, COUNT(*) AS count FROM  
  (SELECT student_id, day, period1 FROM attendance_daily  
   UNION ALL SELECT student_id, day, period2 FROM attendance_daily  
   UNION ALL SELECT student_id, day, period3 FROM attendance_daily  
  ) AS t (id, day, presence)  
GROUP BY id, day, presence ORDER BY id, day, presence ;  

返回

 id |    day     | presence | count 
----+------------+----------+-------
  1 | 2017-01-01 | present  |     3
  2 | 2017-01-01 | absent   |     1
  2 | 2017-01-01 | excused  |     1
  2 | 2017-01-01 | present  |     1

现在您可以例如说,每天缺席 3 次以上?那是错过并得到报告或其他东西。 您现在可以在此表上选择并找出哪位学生在哪一天出席、缺席和缺席了多少次。

现在,如果您出于演示的原因想要将这些行组成一个字符串,那么您可以按照此StackOverflow Answer for SQL-Server。 根据您的 SQL-Server 版本,您也可以只使用 string_agg 函数(如果可用)。

不同的出勤表

如果您将出勤率存储在不同的表架构中,那么使用它会简单得多:

CREATE TABLE attendances (student_id int NOT NULL,  
                         day date NOT NULL,  
                         class int NOT NULL,  
                         period int NOT NULL,  <-- HOUR_X: hour_1 <=> period = 1   
                         presence int NOT NULL);  

--          student_id | day | classes | period AKA hour | presence_status
INSERT INTO attendances VALUES (1, '2017-01-01', 10, 1, 2),
                               (1, '2017-01-01', 10, 2, 1),
                               (1, '2017-01-01', 10, 3, 1),
                               (1, '2017-01-01', 10, 4, 1);

这代表了这样一个事实,即学生 1 在 2017 年 1 月 1 日第 10 课的第一个小时睡过头(第一行缺席 = 2),并且在一天的剩余时间里都在场(状态 = 1)(这意味着最后 3 行中的周期 2、3 和 4)。

然后SELECT 和计数(简单得多):

SELECT student_id, day, class, presence, COUNT( presence ) AS count_presence  
FROM attendances  
GROUP BY student_id, day, class, presence  
ORDER BY 2, 3, 1, 4, 5;  

 student_id |    day     | class | presence | count_presence 
------------+------------+-------+----------+----------------
          1 | 2017-01-01 |    10 |        1 |              3
          1 | 2017-01-01 |    10 |        2 |              1

对于UPDATE,例如将presence 状态设置为hour (period) = 1,例如因为学生迟到了5 分钟(不是他的错):

UPDATE attendances  
SET presence = 1  
WHERE student_id = 1 AND day = '2017-01-01' AND class = 10;  

得到

 student_id |    day     | class | presence | count_presence 
------------+------------+-------+----------+----------------
          1 | 2017-01-01 |    10 |        1 |              4

attendances (student_id, day, class, period, presence) 的建议 PRIMARY UNIQUE KEY 将是 (student_id, day, presence)。 这使每个学生都可以根据需要参加尽可能多的课程和天数。但是对于每个(student, day, presence) 组合,他只能在一个class 中,而恰好是一个presence_status。 这样,学生们每天也可以在不同的班级。

外键参考 这是关于 FK 引用的一些内容。 您只想存储实际存在的学生的出勤率。 换句话说,如果您的attendances_daily 表中有student_id 的行,那么它肯定应该作为学生存在于students 表中。

您可以像这样在创建表时实现这一点(首先创建学生表,否则没有学生ID指向):

CREATE TABLE IF NOT EXISTS attendance_daily (  
student_id int REFERENCES students (student_id),  <-- FOREIGN KEY  
day date, period1 text, period2 text, period3 text);  

或分开

CREATE TABLE IF NOT EXISTS attendance_daily (  
student_id int,  
day date, period1 text, period2 text, period3 text,  
FOREIGN KEY students_id REFERENCES students (student_id)    <-- FOREIGN KEY  
);

您也可以稍后使用ALTER TABLE 添加外键引用。

NULLS 一般来说,你应该努力避免NULLs。 NULL 可能具有模棱两可的含义。这可能意味着数据目前不可用,不存在也永远不会存在,或者作为数字属性中的数字零。关于你的表attendances_dailypresence_status = NULL 是什么意思?和缺席一样吗?原谅?你只是没有数据吗?那你为什么还要存储一行呢?因为您的行存储信息,这些信息可以独立于presence_status?那么你的标准化可能没有看起来那么好?

有时 NULL 也可以。但请仔细考虑是否需要 NULL。它也可以使查询结果令人惊讶。

【讨论】:

  • 非常感谢,顺便说一句,我的表“Attendance_Daily”仅用于存储该班级学生的出勤情况,但不用于存储哪个学生属于哪个班级或学生信息我有,请注意,某些班级或团体每天参加一次“每日出勤”类型,而其他班级每天有 4 小时,而其他班级每天有 2 小时,因此根据班级出勤类型,我们存储班级中配置的所需时间表,但目前我如何计算每个当前表的总小时数:(
  • 好的,所以出席的每日(group_id)实际上是指班级的长度。我稍后会解决这个问题。表 class_duration(class_id int,length int)。出席每日(class_id 的东西在这里)。我会推荐一个通用类表来存储所有可用的类,然后是一个 classes_schedule 表来存储,哪一堂课在哪一天哪几小时上或者类似的东西。现在我将假设所有类都具有相同的长度;可以稍后修复。
  • 不,它不是指班级的长度,而是指时间和日期中分支 x 中的班级 x 以及讲师 x ..etc
  • 我会马上发布这个:当你有时间(可能是明天,下周或其他时间)时,请阅读数据库标准表格。这是一个很好的开胃菜Wikipedia。您应该始终至少达到第三范式 3NF。然后你以后会有很多更少的问题。您有一组重复的 hour_X 列,它(经常)将第一个范式 1NF 置于危险之中。这就是您的查询难以编写的原因!
  • 顺便说一句,这是针对培训课程(文凭、微软课程、英语不同类型的课程)而不是学校课程
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2012-09-26
  • 1970-01-01
  • 2012-04-28
  • 2013-10-14
  • 2014-10-17
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多