使用另一个行创建表的列

时间:2013-10-06 08:37:30

标签: mysql sql database-design pivot-table

我正在处理我的项目[处理学生出勤系统]。我有一个学生列表及其唯一ID [jntuno],我需要在mysql中创建一个数据库,用于存储每个学生每个科目的每日出勤率。所以我用这种方式创建了表格:

我在mysql中有一个表students,其中包含以下字段和数据:

my table contents

现在我想创建一个新表,将jntuno字段中的每个值作为新表的列。

我希望我的新表格[我们将其命名为attendance]以包含这样的列:

+------------+-----------+----------+-----------+-----------+
|11341A0501  |11341A0502 |11341A0503|11341A0504 |11341A0505 |......      
+------------+-----------+----------+-----------+-----------+
|            |           |          |           |           |

如何在mysql中执行此操作?

我稍后会在attendance表中添加3个字段,即:

- > date [教授特定科目的日期],

- > subject [主题的名称]和

- > hours taught [教授特定科目的小时数(可以是1或2或3 ...至6)]

特定subject上教授的每个date都会向row表格添加新的attendance

示例:

+------------+-----------+-----------------+------------+-----------+----------+-----------+-----------+
|date        |subject    | classes taught  |11341A0501  |11341A0502 |11341A0503|11341A0504 |11341A0505 |..    
+------------+-----------+-----------------+------------+-----------+----------+-----------+-----------+
|2013-09-31  |OOPS       |3                |2           |3          |0         |1          |3          |

我以这种方式选择表格,以便更快地输入表格。

但是很多人称之为 BAD DATABASE STRUCTURE 。所以请建议我,如果我的问题有其他一些好的和有效的数据库设计

8 个答案:

答案 0 :(得分:3)

此程序将完成工作:

DELIMITER ||
DROP PROCEDURE IF EXISTS `test`.`pivot`;
CREATE PROCEDURE `test`.`pivot`()
    MODIFIES SQL DATA
BEGIN
    DROP TABLE IF EXISTS `test`.`new_table`;
    SELECT GROUP_CONCAT(CONCAT(`jntunno`, ' CHAR(10) NOT NULL') SEPARATOR ', ') FROM `test`.`students` INTO @sql;
    SET @sql := CONCAT('CREATE TABLE `test`.`new_table` (', @sql, ') ENGINE=InnoDB;');
    PREPARE stmt FROM @sql;
    EXECUTE stmt;
    DEALLOCATE PREPARE stmt;
    SET @sql := NULL;
END;
||
DELIMITER ;

如果您无法使用存储过程,则可以轻松地将该代码转换为PHP或您使用的任何语言。

答案 1 :(得分:3)

使用以下语句创建新表:

select @s:=concat('create table students_col (',group_concat(jntunno,' CHAR(10)' order by slno),')') from students;
prepare stmt from @s;
execute stmt;
deallocate prepare stmt;

观察使用CREATE TABLE

构建group_concat的方式

演示:SQL Fiddle

如果您还想插入名称,这是它的声明:

select @s:=concat('insert into students_col values (',group_concat(concat('"',name,'"') order by slno),')') from students;
prepare stmt from @s;
execute stmt;
deallocate prepare stmt;
select * from students_col;

以下是我的全部内容:

mysql> drop table if exists students;
Query OK, 0 rows affected (0.00 sec)

mysql> create table students (slno integer, jntunno char(10), name varchar(50));
Query OK, 0 rows affected (0.07 sec)

mysql> insert into students values (1,'1134A0501','ADARI GOPI');
Query OK, 1 row affected (0.00 sec)

mysql> insert into students values (2,'1134A0502','BALU');
Query OK, 1 row affected (0.00 sec)

mysql> insert into students values (3,'1134A0503','GEETHA');
Query OK, 1 row affected (0.00 sec)

mysql> drop table if exists students_col;
Query OK, 0 rows affected (0.00 sec)

mysql> select @s:=concat('create table students_col (',group_concat(jntunno,' CHAR(10)' order by slno),')') from students;
+-----------------------------------------------------------------------------------------------+
| @s:=concat('create table students_col (',group_concat(jntunno,' CHAR(10)' order by slno),')') |
+-----------------------------------------------------------------------------------------------+
| create table students_col (1134A0501 CHAR(10),1134A0502 CHAR(10),1134A0503 CHAR(10))          |
+-----------------------------------------------------------------------------------------------+
1 row in set (0.00 sec)

mysql> prepare stmt from @s;
Query OK, 0 rows affected (0.00 sec)
Statement prepared

mysql> execute stmt;
Query OK, 0 rows affected (0.21 sec)

mysql> deallocate prepare stmt;
Query OK, 0 rows affected (0.01 sec)

mysql> 
mysql> select @s:=concat('insert into students_col values (',group_concat(concat('"',name,'"') order by slno),')') from students;
+------------------------------------------------------------------------------------------------------+
| @s:=concat('insert into students_col values (',group_concat(concat('"',name,'"') order by slno),')') |
+------------------------------------------------------------------------------------------------------+
| insert into students_col values ("ADARI GOPI","BALU","GEETHA")                                       |
+------------------------------------------------------------------------------------------------------+
1 row in set (0.00 sec)

mysql> prepare stmt from @s;
Query OK, 0 rows affected (0.00 sec)
Statement prepared

mysql> execute stmt;
Query OK, 1 row affected (0.00 sec)

mysql> deallocate prepare stmt;
Query OK, 0 rows affected (0.00 sec)

mysql> 
mysql> select * from students_col;
+------------+-----------+-----------+
| 1134A0501  | 1134A0502 | 1134A0503 |
+------------+-----------+-----------+
| ADARI GOPI | BALU      | GEETHA    |
+------------+-----------+-----------+
1 row in set (0.00 sec)

mysql> 

答案 2 :(得分:0)

create table new_table
select distinct jntuno from students;

create table new_table (jntuno varchar(10));
insert into new_table 
select distinct jntuno from students;

答案 3 :(得分:0)

create table new_table (jntuno varchar(10),fieldsname varchar(10));
insert into new_table(jntuno,fieldsname)
values(select distinct jntuno from s tudents,'test');

答案 4 :(得分:0)

我将尝试回答您如何更好地设计此数据库的问题:

说明: 我应该将表格设置为每天为每个学生x设置一行,而不是为每个学生设置一个列,并且每天假设一行,您可以使用外键来强制执行数据完整性

这主要是因为学生人数不是静态数字。为了在这样的设置中优化您的数据使用,您基本上需要在每次添加或删除学生时重新创建表。 因此,如果您从30名学生开始,那么您将拥有一个包含30列的表格,如果每次添加记录时学生数量将减少到15,您将创建15个未使用的值,这将逐渐占用比您更多的存储空间实际需要。

解决方案: 如果您按照以下方式构建出勤表:

attendance ID | JNTUNO | Date | Subject | Hours

考勤ID只是该行的唯一标识符,我建议使用guid或auto增加的int

JNTUNO将是一个外键,指向你的学生表

这种方式在我之前介绍的场景中,有30名学生,每天会添加30行,每行5个值,但当你的学生数量变为15时,你只能添加15行。

我不太了解MYSQL语法但是如果你愿意,如果我的解释不清楚,我可以尝试拼凑一个具体的实现;请告诉我。

答案 5 :(得分:0)

declare @s as varchar(8000);
declare @s2 as varchar(25);
 set @s ='create table attendance (';
 declare s1  cursor
 for 
 select jntunno from students  
 OPEN s1 
    fetch next from s1 into @s2 
    set @s = @s +'['+@s2 +'] numeric(4,2)'
    fetch next from s1 into @s2
     WHILE @@FETCH_STATUS = 0
     BEGIN
         set @s = @s +',['+@s2 +'] numeric(4,2)'
         fetch next from s1 into @s2
     end
 CLOSE s1 -- close the cursor
DEALLOCATE s1
set @s = @s+')'
exec(@s)

答案 6 :(得分:0)

您不希望每次添加学生时都添加列。

我的设计是这样的:

Table:  Attendance
    Columns:
        Date
        Subject
        ClassNumber
        Missed_jntuno

然后为每个错过的学生/班级组合添加一行(或者,如果学生错过的次数超过他们参加,您可能希望将其翻转到Attended_jntuno字段,并在他们制作时添加该行它上课 - 或者如果你真的感觉最完整,总是为每个学生写一行,然后为参加或不参加其他位/布尔列。)

这种方式的一个优点是,您可以看到哪些课程除了每日总和之外还有哪些学生。另一个原因是,对于灵活的报告,这对OLAP多维数据集这样的事情要友好得多。

答案 7 :(得分:0)

基本的数据库设计现在正在跳起来并大声喊叫:“你做错了!”。

你在这里尝试做的是在1个表中放置多对多的关系,而它实际上应该在3个表中。

你应该做的是保持你的学生表原样并为每个科目添加一行subjects表,但不包括日期。

然后你想要另一个表Attendance,其中包含学生ID的参考列,主题ID的参考列,日期字段和存在字段。

您现在正在尝试做的是尝试将基本上不稳定的数据存储在有关您的表的元数据中,这是您永远不应该做的。例如,如果您有一名学生在入学一周后加入您的学校怎么办?然后你的表突然得到一个额外的列,第一周没有值。

此外,您的系统意味着数据库查询要困难得多,因为您要在列标题中存储要过滤的数据。这里的其他人给出了一些不好主意的原因。