【问题标题】:Creating columns of a table using the rows of another使用另一个表的行创建表的列
【发布时间】:2013-10-06 08:37:30
【问题描述】:

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

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

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

我希望我的新表 [让我们将其命名为 attendance] 具有这样的列:

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

如何在 mysql 中做到这一点?

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

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

->subject[所教科目的名称]和

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

针对特定date 教授的每个subject 都会在attendance 表中添加一个新row

示例:

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

我这样选桌,是为了让考勤进入桌更快捷。

但许多人称之为糟糕的数据库结构。所以如果我的问题有其他好的和有效的数据库设计,请建议我

【问题讨论】:

  • 这通常不是一个精心设计的模型。你确定有一个规范化的数据库模式吗?
  • 这类问题有替代方案吗?如果是这样,请建议我
  • 如果您想存储有关学生的数据,只需在新表中添加 student_id。将其定义为student 表的外键。也许this 可以帮助你。
  • 您可以在之前的表中插入任何新条目时,对新表使用alter table。
  • 不怎么样,告诉我们为什么要将 student_id 作为列名,如果您的表增长到 5K 学生 id,那么您会创建 5k 行的表吗?糟糕的设计。

标签: mysql sql database-design pivot-table


【解决方案1】:

使用以下语句创建新表:

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> 

【讨论】:

  • 太棒了! ....你能不能给我推荐一些更好的数据库设计来解决这种情况!
  • 我想知道你为什么需要这么多列。如果我知道你真正打算做什么,我会建议你一些事情。老实说,我不会创建这样的表。假设您要填充这样的 HTML 表格,那么我宁愿阅读现有表格并使用例如 PHP 或其他一些服务器端语言构建 HTML 输出。
  • 请再次检查我的问题@hol。我已经更新了描述
  • 不要做一个有那么多列的表,只要两个表并连接它们。如果您不知道该怎么做,请尝试阅读一些有关数据库的基本文献,当您遇到困难时,请创建一个 问题。然后,当您需要为每个学生显示带有列的 PHP 页面并且您不知道该怎么做时,再次学习一些基础知识,如果您无法弄清楚,那么创建一个 new 问题.不要期望在经过编辑和编辑的问题上得到答案。我为自己说话,但也许其他人也有同感,这有点令人沮丧。
【解决方案2】:

这个程序将完成工作:

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 或您使用的任何语言。

【讨论】:

  • 太棒了! ....你能不能给我推荐一些更好的数据库设计来解决这种情况!
  • 您想使用的设计可能是好是坏,这取决于您需要做什么。数据库的设计应该能够快速回答您的查询。因此,在提出设计建议之前,我(或任何人)确实需要了解您的疑问
【解决方案3】:
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;

【讨论】:

  • 您提供的解决方案创建了一个新表,其中jntuno 作为列,并从students 表中导入该字段的所有值...这不是我想要的!...我希望每个行值成为我的新表的一列
  • 我明白了。不要那样做。这真是糟糕的数据库设计。
  • 这类问题有替代方案吗?
  • 我不知道。您实际上没有描述您的问题。
  • 是的……在这里描述我的问题太长了……我会提出一个关于表和列选择的新问题……谢谢
【解决方案4】:

试试

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

【讨论】:

  • 我明白了。不要那样做。这真是糟糕的数据库设计
  • “不相关”并不意味着“糟糕的设计”。这取决于他需要做什么。
【解决方案5】:

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

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

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

解决方案: 如果您像这样构建出勤表:

attendance ID | JNTUNO | Date | Subject | Hours

出席 id 将只是该行的唯一标识符,我建议使用 guid 或自动递增的 int

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

在我之前介绍的场景中,如果有 30 名学生,您每天将添加 30 行,每行有 5 个值,但是当您的学生人数变为 15 时,您只添加 15 行。

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

【讨论】:

    【解决方案6】:

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

    我会这样设计:

    Table:  Attendance
        Columns:
            Date
            Subject
            ClassNumber
            Missed_jntuno
    

    然后,您为每个错过的学生/班级组合添加一行(或者,如果学生错过的次数超过他们参加的次数,您可能希望将其翻转到 Attended_jntuno 字段,并在他们成功时添加该行课堂——或者如果你真的感觉最完整,总是为每个学生写一行,然后有另一个位/布尔列代表出席与否。

    这种方式的一个好处是,除了每日总和之外,您还可以查看哪些班级获得了哪些学生。另一个原因是这对于灵活报告的 OLAP 多维数据集更加友好。

    【讨论】:

      【解决方案7】:
      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)
      

      【讨论】:

        【解决方案8】:

        基本的数据库设计现在正在跳起来,当着你的面大喊:“你做错了!”。

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

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

        然后您想要另一个表 Attendance,其中包含学生 ID 的引用列、主题 ID 的引用列、日期字段和状态字段。

        您现在要做的是尝试在有关您的表的元数据中存储基本上易变的数据,这是您永远不应该做的。例如,如果您有一个学生在入学 1 周后加入您的学校怎么办?然后你的表突然多了一个第一周没有值的列。

        此外,您的系统意味着数据库查询要困难得多,因为您将要过滤的数据存储在列标题中。这里的其他人给出了许多理由说明这是一个坏主意。

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2017-09-26
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2013-05-01
          • 2014-04-12
          相关资源
          最近更新 更多